github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/notify_router.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 7 "fmt" 8 "sync" 9 "time" 10 11 "github.com/keybase/client/go/protocol/chat1" 12 "github.com/keybase/client/go/protocol/keybase1" 13 stellar1 "github.com/keybase/client/go/protocol/stellar1" 14 "github.com/keybase/go-framed-msgpack-rpc/rpc" 15 context "golang.org/x/net/context" 16 ) 17 18 // NotifyListener provides hooks for listening for when 19 // notifications are called. It is intended to simplify 20 // testing notifications. 21 type NotifyListener interface { 22 Logout() 23 Login(username string) 24 ClientOutOfDate(to, uri, msg string) 25 UserChanged(uid keybase1.UID) 26 TrackingChanged(uid keybase1.UID, username NormalizedUsername) 27 TrackingInfo(uid keybase1.UID, followers, followees []string) 28 FSOnlineStatusChanged(online bool) 29 FSActivity(activity keybase1.FSNotification) 30 FSPathUpdated(path string) 31 FSEditListResponse(arg keybase1.FSEditListArg) 32 FSSyncStatusResponse(arg keybase1.FSSyncStatusArg) 33 FSSyncEvent(arg keybase1.FSPathSyncStatus) 34 FSEditListRequest(arg keybase1.FSEditListRequest) 35 FSOverallSyncStatusChanged(arg keybase1.FolderSyncStatus) 36 FSFavoritesChanged() 37 FavoritesChanged(uid keybase1.UID) 38 FSSubscriptionNotify(arg keybase1.FSSubscriptionNotifyArg) 39 FSSubscriptionNotifyPath(arg keybase1.FSSubscriptionNotifyPathArg) 40 SimpleFSArchiveStatusChanged(status keybase1.SimpleFSArchiveStatus) 41 PaperKeyCached(uid keybase1.UID, encKID keybase1.KID, sigKID keybase1.KID) 42 KeyfamilyChanged(uid keybase1.UID) 43 NewChatActivity(uid keybase1.UID, activity chat1.ChatActivity, source chat1.ChatActivitySource) 44 NewChatKBFSFileEditActivity(uid keybase1.UID, activity chat1.ChatActivity) 45 ChatIdentifyUpdate(update keybase1.CanonicalTLFNameAndIDWithBreaks) 46 ChatTLFFinalize(uid keybase1.UID, convID chat1.ConversationID, 47 finalizeInfo chat1.ConversationFinalizeInfo) 48 ChatTLFResolve(uid keybase1.UID, convID chat1.ConversationID, 49 resolveInfo chat1.ConversationResolveInfo) 50 ChatInboxStale(uid keybase1.UID) 51 ChatThreadsStale(uid keybase1.UID, updates []chat1.ConversationStaleUpdate) 52 ChatInboxSynced(uid keybase1.UID, topicType chat1.TopicType, syncRes chat1.ChatSyncResult) 53 ChatInboxSyncStarted(uid keybase1.UID) 54 ChatTypingUpdate([]chat1.ConvTypingUpdate) 55 ChatJoinedConversation(uid keybase1.UID, convID chat1.ConversationID, conv *chat1.InboxUIItem) 56 ChatLeftConversation(uid keybase1.UID, convID chat1.ConversationID) 57 ChatResetConversation(uid keybase1.UID, convID chat1.ConversationID) 58 ChatSetConvRetention(uid keybase1.UID, convID chat1.ConversationID) 59 ChatSetTeamRetention(uid keybase1.UID, teamID keybase1.TeamID) 60 ChatSetConvSettings(uid keybase1.UID, convID chat1.ConversationID) 61 ChatSubteamRename(uid keybase1.UID, convIDs []chat1.ConversationID) 62 ChatKBFSToImpteamUpgrade(uid keybase1.UID, convID chat1.ConversationID) 63 ChatAttachmentUploadStart(uid keybase1.UID, convID chat1.ConversationID, outboxID chat1.OutboxID) 64 ChatAttachmentUploadProgress(uid keybase1.UID, convID chat1.ConversationID, outboxID chat1.OutboxID, 65 bytesComplete, bytesTotal int64) 66 ChatAttachmentDownloadProgress(uid keybase1.UID, convID chat1.ConversationID, msgID chat1.MessageID, 67 bytesComplete, bytesTotal int64) 68 ChatAttachmentDownloadComplete(uid keybase1.UID, convID chat1.ConversationID, msgID chat1.MessageID) 69 ChatArchiveProgress(jobID chat1.ArchiveJobID, 70 messagesComplete, messagesTotal int64) 71 ChatArchiveComplete(jobID chat1.ArchiveJobID) 72 ChatPaymentInfo(uid keybase1.UID, convID chat1.ConversationID, msgID chat1.MessageID, info chat1.UIPaymentInfo) 73 ChatRequestInfo(uid keybase1.UID, convID chat1.ConversationID, msgID chat1.MessageID, info chat1.UIRequestInfo) 74 ChatPromptUnfurl(uid keybase1.UID, convID chat1.ConversationID, msgID chat1.MessageID, domain string) 75 ChatConvUpdate(uid keybase1.UID, convID chat1.ConversationID) 76 ChatWelcomeMessageLoaded(teamID keybase1.TeamID, message chat1.WelcomeMessageDisplay) 77 ChatParticipantsInfo(participants map[chat1.ConvIDStr][]chat1.UIParticipant) 78 PGPKeyInSecretStoreFile() 79 BadgeState(badgeState keybase1.BadgeState) 80 ReachabilityChanged(r keybase1.Reachability) 81 TeamChangedByID(teamID keybase1.TeamID, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, latestHiddenSeqno keybase1.Seqno, source keybase1.TeamChangedSource) 82 TeamChangedByName(teamName string, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, latestHiddenSeqno keybase1.Seqno, source keybase1.TeamChangedSource) 83 TeamDeleted(teamID keybase1.TeamID) 84 TeamRoleMapChanged(version keybase1.UserTeamVersion) 85 UserBlocked(b keybase1.UserBlockedBody) 86 TeamExit(teamID keybase1.TeamID) 87 NewlyAddedToTeam(teamID keybase1.TeamID) 88 NewTeamEK(teamID keybase1.TeamID, generation keybase1.EkGeneration) 89 NewTeambotEK(teamID keybase1.TeamID, generation keybase1.EkGeneration) 90 TeambotEKNeeded(teamID keybase1.TeamID, botUID keybase1.UID, generation keybase1.EkGeneration, forceCreateGen *keybase1.EkGeneration) 91 NewTeambotKey(teamID keybase1.TeamID, generation keybase1.TeambotKeyGeneration) 92 TeambotKeyNeeded(teamID keybase1.TeamID, botUID keybase1.UID, generation keybase1.TeambotKeyGeneration) 93 AvatarUpdated(name string, formats []keybase1.AvatarFormat) 94 DeviceCloneCountChanged(newClones int) 95 WalletPaymentNotification(accountID stellar1.AccountID, paymentID stellar1.PaymentID) 96 WalletPaymentStatusNotification(accountID stellar1.AccountID, paymentID stellar1.PaymentID) 97 WalletRequestStatusNotification(reqID stellar1.KeybaseRequestID) 98 WalletAccountDetailsUpdate(accountID stellar1.AccountID, account stellar1.WalletAccountLocal) 99 WalletAccountsUpdate(accounts []stellar1.WalletAccountLocal) 100 WalletPendingPaymentsUpdate(accountID stellar1.AccountID, pending []stellar1.PaymentOrErrorLocal) 101 WalletRecentPaymentsUpdate(accountID stellar1.AccountID, firstPage stellar1.PaymentsPageLocal) 102 TeamMetadataUpdate() 103 CanUserPerformChanged(teamName string) 104 PhoneNumbersChanged(list []keybase1.UserPhoneNumber, category string, phoneNumber keybase1.PhoneNumber) 105 EmailAddressVerified(emailAddress keybase1.EmailAddress) 106 EmailsChanged(list []keybase1.Email, category string, email keybase1.EmailAddress) 107 PasswordChanged() 108 RootAuditError(msg string) 109 BoxAuditError(msg string) 110 RuntimeStatsUpdate(*keybase1.RuntimeStats) 111 HTTPSrvInfoUpdate(keybase1.HttpSrvInfo) 112 HandleKeybaseLink(link string, deferred bool) 113 IdentifyUpdate(okUsernames []string, brokenUsernames []string) 114 Reachability(keybase1.Reachability) 115 FeaturedBotsUpdate(bots []keybase1.FeaturedBot, limit, offset int) 116 SaltpackOperationStart(opType keybase1.SaltpackOperationType, filename string) 117 SaltpackOperationProgress(opType keybase1.SaltpackOperationType, filename string, bytesComplete, bytesTotal int64) 118 SaltpackOperationDone(opType keybase1.SaltpackOperationType, filename string) 119 UpdateInviteCounts(keybase1.InviteCounts) 120 TeamTreeMembershipsPartial(keybase1.TeamTreeMembership) 121 TeamTreeMembershipsDone(keybase1.TeamTreeMembershipsDoneResult) 122 WebOfTrustChanged(username string) 123 } 124 125 type NoopNotifyListener struct{} 126 127 var _ NotifyListener = (*NoopNotifyListener)(nil) 128 129 func (n *NoopNotifyListener) Logout() {} 130 func (n *NoopNotifyListener) Login(username string) {} 131 func (n *NoopNotifyListener) ClientOutOfDate(to, uri, msg string) {} 132 func (n *NoopNotifyListener) UserChanged(uid keybase1.UID) {} 133 func (n *NoopNotifyListener) TrackingChanged(uid keybase1.UID, username NormalizedUsername) {} 134 func (n *NoopNotifyListener) TrackingInfo(uid keybase1.UID, followers, followees []string) {} 135 func (n *NoopNotifyListener) FSOnlineStatusChanged(online bool) {} 136 func (n *NoopNotifyListener) FSOverallSyncStatusChanged(status keybase1.FolderSyncStatus) {} 137 func (n *NoopNotifyListener) FSFavoritesChanged() {} 138 func (n *NoopNotifyListener) FSActivity(activity keybase1.FSNotification) {} 139 func (n *NoopNotifyListener) FSPathUpdated(path string) {} 140 func (n *NoopNotifyListener) FSEditListResponse(arg keybase1.FSEditListArg) {} 141 func (n *NoopNotifyListener) FSSyncStatusResponse(arg keybase1.FSSyncStatusArg) {} 142 func (n *NoopNotifyListener) FSSyncEvent(arg keybase1.FSPathSyncStatus) {} 143 func (n *NoopNotifyListener) FSEditListRequest(arg keybase1.FSEditListRequest) {} 144 func (n *NoopNotifyListener) FavoritesChanged(uid keybase1.UID) {} 145 func (n *NoopNotifyListener) FSSubscriptionNotify(arg keybase1.FSSubscriptionNotifyArg) { 146 } 147 func (n *NoopNotifyListener) FSSubscriptionNotifyPath(arg keybase1.FSSubscriptionNotifyPathArg) { 148 } 149 func (n *NoopNotifyListener) SimpleFSArchiveStatusChanged(status keybase1.SimpleFSArchiveStatus) { 150 } 151 func (n *NoopNotifyListener) PaperKeyCached(uid keybase1.UID, encKID keybase1.KID, sigKID keybase1.KID) { 152 } 153 func (n *NoopNotifyListener) KeyfamilyChanged(uid keybase1.UID) {} 154 func (n *NoopNotifyListener) NewChatActivity(uid keybase1.UID, activity chat1.ChatActivity, 155 source chat1.ChatActivitySource) { 156 } 157 func (n *NoopNotifyListener) NewChatKBFSFileEditActivity(uid keybase1.UID, activity chat1.ChatActivity) { 158 } 159 func (n *NoopNotifyListener) ChatIdentifyUpdate(update keybase1.CanonicalTLFNameAndIDWithBreaks) {} 160 func (n *NoopNotifyListener) ChatTLFFinalize(uid keybase1.UID, convID chat1.ConversationID, 161 finalizeInfo chat1.ConversationFinalizeInfo) { 162 } 163 func (n *NoopNotifyListener) ChatTLFResolve(uid keybase1.UID, convID chat1.ConversationID, 164 resolveInfo chat1.ConversationResolveInfo) { 165 } 166 func (n *NoopNotifyListener) ChatInboxStale(uid keybase1.UID) {} 167 func (n *NoopNotifyListener) ChatThreadsStale(uid keybase1.UID, updates []chat1.ConversationStaleUpdate) { 168 } 169 func (n *NoopNotifyListener) ChatInboxSynced(uid keybase1.UID, topicType chat1.TopicType, 170 syncRes chat1.ChatSyncResult) { 171 } 172 func (n *NoopNotifyListener) ChatInboxSyncStarted(uid keybase1.UID) {} 173 func (n *NoopNotifyListener) ChatTypingUpdate([]chat1.ConvTypingUpdate) {} 174 func (n *NoopNotifyListener) ChatJoinedConversation(uid keybase1.UID, convID chat1.ConversationID, 175 conv *chat1.InboxUIItem) { 176 } 177 func (n *NoopNotifyListener) ChatLeftConversation(uid keybase1.UID, convID chat1.ConversationID) {} 178 func (n *NoopNotifyListener) ChatResetConversation(uid keybase1.UID, convID chat1.ConversationID) {} 179 func (n *NoopNotifyListener) Chat(uid keybase1.UID, convID chat1.ConversationID) {} 180 func (n *NoopNotifyListener) ChatSetConvRetention(uid keybase1.UID, convID chat1.ConversationID) {} 181 func (n *NoopNotifyListener) ChatSetTeamRetention(uid keybase1.UID, teamID keybase1.TeamID) {} 182 func (n *NoopNotifyListener) ChatSetConvSettings(uid keybase1.UID, convID chat1.ConversationID) {} 183 func (n *NoopNotifyListener) ChatSubteamRename(uid keybase1.UID, convIDs []chat1.ConversationID) {} 184 func (n *NoopNotifyListener) ChatKBFSToImpteamUpgrade(uid keybase1.UID, convID chat1.ConversationID) { 185 } 186 func (n *NoopNotifyListener) ChatAttachmentUploadStart(uid keybase1.UID, convID chat1.ConversationID, 187 outboxID chat1.OutboxID) { 188 } 189 func (n *NoopNotifyListener) ChatAttachmentUploadProgress(uid keybase1.UID, convID chat1.ConversationID, 190 outboxID chat1.OutboxID, bytesComplete, bytesTotal int64) { 191 } 192 func (n *NoopNotifyListener) ChatAttachmentDownloadProgress(uid keybase1.UID, convID chat1.ConversationID, 193 msgID chat1.MessageID, bytesComplete, bytesTotal int64) { 194 } 195 func (n *NoopNotifyListener) ChatAttachmentDownloadComplete(uid keybase1.UID, convID chat1.ConversationID, 196 msgID chat1.MessageID) { 197 } 198 func (n *NoopNotifyListener) ChatArchiveProgress(jobID chat1.ArchiveJobID, messagesComplete, messagesTotal int64) { 199 } 200 func (n *NoopNotifyListener) ChatArchiveComplete(jobID chat1.ArchiveJobID) { 201 } 202 func (n *NoopNotifyListener) ChatPaymentInfo(uid keybase1.UID, convID chat1.ConversationID, 203 msgID chat1.MessageID, info chat1.UIPaymentInfo) { 204 } 205 func (n *NoopNotifyListener) ChatRequestInfo(uid keybase1.UID, convID chat1.ConversationID, 206 msgID chat1.MessageID, info chat1.UIRequestInfo) { 207 } 208 func (n *NoopNotifyListener) ChatPromptUnfurl(uid keybase1.UID, convID chat1.ConversationID, 209 msgID chat1.MessageID, domain string) { 210 } 211 func (n *NoopNotifyListener) ChatConvUpdate(uid keybase1.UID, convID chat1.ConversationID) {} 212 func (n *NoopNotifyListener) ChatWelcomeMessageLoaded(keybase1.TeamID, chat1.WelcomeMessageDisplay) {} 213 func (n *NoopNotifyListener) ChatParticipantsInfo( 214 participants map[chat1.ConvIDStr][]chat1.UIParticipant) { 215 } 216 217 func (n *NoopNotifyListener) PGPKeyInSecretStoreFile() {} 218 func (n *NoopNotifyListener) BadgeState(badgeState keybase1.BadgeState) {} 219 func (n *NoopNotifyListener) ReachabilityChanged(r keybase1.Reachability) {} 220 func (n *NoopNotifyListener) TeamChangedByID(teamID keybase1.TeamID, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, latestHiddenSeqno keybase1.Seqno, source keybase1.TeamChangedSource) { 221 } 222 func (n *NoopNotifyListener) TeamChangedByName(teamName string, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, latestHiddenSeqno keybase1.Seqno, source keybase1.TeamChangedSource) { 223 } 224 func (n *NoopNotifyListener) TeamDeleted(teamID keybase1.TeamID) {} 225 func (n *NoopNotifyListener) TeamExit(teamID keybase1.TeamID) {} 226 func (n *NoopNotifyListener) TeamRoleMapChanged(version keybase1.UserTeamVersion) {} 227 func (n *NoopNotifyListener) NewTeamEK(teamID keybase1.TeamID, generation keybase1.EkGeneration) {} 228 func (n *NoopNotifyListener) NewTeambotEK(teamID keybase1.TeamID, generation keybase1.EkGeneration) {} 229 func (n *NoopNotifyListener) TeambotEKNeeded(teamID keybase1.TeamID, botUID keybase1.UID, 230 generation keybase1.EkGeneration, forceCreateGen *keybase1.EkGeneration) { 231 } 232 func (n *NoopNotifyListener) NewTeambotKey(teamID keybase1.TeamID, generation keybase1.TeambotKeyGeneration) { 233 } 234 func (n *NoopNotifyListener) TeambotKeyNeeded(teamID keybase1.TeamID, botUID keybase1.UID, 235 generation keybase1.TeambotKeyGeneration) { 236 } 237 func (n *NoopNotifyListener) NewlyAddedToTeam(teamID keybase1.TeamID) {} 238 func (n *NoopNotifyListener) AvatarUpdated(name string, formats []keybase1.AvatarFormat) {} 239 func (n *NoopNotifyListener) DeviceCloneCountChanged(newClones int) {} 240 func (n *NoopNotifyListener) WalletPaymentNotification(accountID stellar1.AccountID, paymentID stellar1.PaymentID) { 241 } 242 func (n *NoopNotifyListener) WalletPaymentStatusNotification(accountID stellar1.AccountID, paymentID stellar1.PaymentID) { 243 } 244 func (n *NoopNotifyListener) WalletRequestStatusNotification(reqID stellar1.KeybaseRequestID) {} 245 func (n *NoopNotifyListener) WalletAccountDetailsUpdate(accountID stellar1.AccountID, account stellar1.WalletAccountLocal) { 246 } 247 func (n *NoopNotifyListener) WalletAccountsUpdate(accounts []stellar1.WalletAccountLocal) {} 248 func (n *NoopNotifyListener) WalletPendingPaymentsUpdate(accountID stellar1.AccountID, pending []stellar1.PaymentOrErrorLocal) { 249 } 250 func (n *NoopNotifyListener) WalletRecentPaymentsUpdate(accountID stellar1.AccountID, firstPage stellar1.PaymentsPageLocal) { 251 } 252 func (n *NoopNotifyListener) TeamMetadataUpdate() {} 253 func (n *NoopNotifyListener) CanUserPerformChanged(teamName string) {} 254 func (n *NoopNotifyListener) PhoneNumbersChanged(list []keybase1.UserPhoneNumber, category string, phoneNumber keybase1.PhoneNumber) { 255 } 256 func (n *NoopNotifyListener) EmailAddressVerified(emailAddress keybase1.EmailAddress) {} 257 func (n *NoopNotifyListener) EmailsChanged(list []keybase1.Email, category string, email keybase1.EmailAddress) { 258 } 259 func (n *NoopNotifyListener) PasswordChanged() {} 260 func (n *NoopNotifyListener) RootAuditError(msg string) {} 261 func (n *NoopNotifyListener) BoxAuditError(msg string) {} 262 func (n *NoopNotifyListener) RuntimeStatsUpdate(*keybase1.RuntimeStats) {} 263 func (n *NoopNotifyListener) HTTPSrvInfoUpdate(keybase1.HttpSrvInfo) {} 264 func (n *NoopNotifyListener) HandleKeybaseLink(link string, deferred bool) {} 265 func (n *NoopNotifyListener) IdentifyUpdate(okUsernames []string, brokenUsernames []string) { 266 } 267 func (n *NoopNotifyListener) Reachability(keybase1.Reachability) {} 268 func (n *NoopNotifyListener) UserBlocked(keybase1.UserBlockedBody) {} 269 func (n *NoopNotifyListener) FeaturedBotsUpdate(bots []keybase1.FeaturedBot, limit, offset int) {} 270 func (n *NoopNotifyListener) SaltpackOperationStart(opType keybase1.SaltpackOperationType, filename string) { 271 } 272 func (n *NoopNotifyListener) SaltpackOperationProgress(opType keybase1.SaltpackOperationType, filename string, bytesComplete, bytesTotal int64) { 273 } 274 func (n *NoopNotifyListener) SaltpackOperationDone(opType keybase1.SaltpackOperationType, filename string) { 275 } 276 func (n *NoopNotifyListener) UpdateInviteCounts(keybase1.InviteCounts) { 277 } 278 func (n *NoopNotifyListener) TeamTreeMembershipsPartial(keybase1.TeamTreeMembership) {} 279 func (n *NoopNotifyListener) TeamTreeMembershipsDone(keybase1.TeamTreeMembershipsDoneResult) {} 280 func (n *NoopNotifyListener) WebOfTrustChanged(username string) { 281 } 282 283 type NotifyListenerID string 284 285 // NotifyRouter routes notifications to the various active RPC 286 // connections. It's careful only to route to those who are interested 287 type NotifyRouter struct { 288 sync.Mutex 289 Contextified 290 cm *ConnectionManager 291 state map[ConnectionID]keybase1.NotificationChannels 292 listeners map[NotifyListenerID]NotifyListener 293 } 294 295 // NewNotifyRouter makes a new notification router; we should only 296 // make one of these per process. 297 func NewNotifyRouter(g *GlobalContext) *NotifyRouter { 298 return &NotifyRouter{ 299 Contextified: NewContextified(g), 300 cm: g.ConnectionManager, 301 state: make(map[ConnectionID]keybase1.NotificationChannels), 302 listeners: make(map[NotifyListenerID]NotifyListener), 303 } 304 } 305 306 func (n *NotifyRouter) AddListener(listener NotifyListener) NotifyListenerID { 307 n.Lock() 308 defer n.Unlock() 309 id := NotifyListenerID(RandStringB64(3)) 310 n.listeners[id] = listener 311 return id 312 } 313 314 func (n *NotifyRouter) RemoveListener(id NotifyListenerID) { 315 n.Lock() 316 defer n.Unlock() 317 delete(n.listeners, id) 318 } 319 320 func (n *NotifyRouter) Shutdown() {} 321 322 func (n *NotifyRouter) setNotificationChannels(id ConnectionID, val keybase1.NotificationChannels) { 323 n.Lock() 324 defer n.Unlock() 325 n.state[id] = val 326 } 327 328 func (n *NotifyRouter) getNotificationChannels(id ConnectionID) keybase1.NotificationChannels { 329 n.Lock() 330 defer n.Unlock() 331 return n.state[id] 332 } 333 334 // GetChannels retrieves which notification channels a connection is interested it 335 // given its ID. 336 func (n *NotifyRouter) GetChannels(i ConnectionID) keybase1.NotificationChannels { 337 return n.getNotificationChannels(i) 338 } 339 340 func (n *NotifyRouter) runListeners(f func(listener NotifyListener)) { 341 var listeners []NotifyListener 342 n.Lock() 343 for _, l := range n.listeners { 344 listeners = append(listeners, l) 345 } 346 n.Unlock() 347 for _, l := range listeners { 348 f(l) 349 } 350 } 351 352 // AddConnection should be called every time there's a new RPC connection 353 // established for this server. The caller should pass in the Transporter 354 // and also the channel that will get messages when the channel closes. 355 func (n *NotifyRouter) AddConnection(xp rpc.Transporter, ch chan error) ConnectionID { 356 if n == nil { 357 return 0 358 } 359 id := n.cm.AddConnection(xp, ch) 360 n.setNotificationChannels(id, keybase1.NotificationChannels{}) 361 return id 362 } 363 364 // SetChannels sets which notification channels are interested for the connection 365 // with the given connection ID. 366 func (n *NotifyRouter) SetChannels(i ConnectionID, nc keybase1.NotificationChannels) { 367 n.setNotificationChannels(i, nc) 368 } 369 370 // HandleLogout is called whenever the current user logged out. It will broadcast 371 // the message to all connections who care about such a message. 372 func (n *NotifyRouter) HandleLogout(ctx context.Context) { 373 if n == nil { 374 return 375 } 376 defer n.G().CTrace(ctx, "NotifyRouter#HandleLogout", nil)() 377 ctx = CopyTagsToBackground(ctx) 378 // For all connections we currently have open... 379 n.cm.ApplyAllDetails(func(id ConnectionID, xp rpc.Transporter, d *keybase1.ClientDetails) bool { 380 // If the connection wants the `Session` notification type 381 registered := false 382 if n.getNotificationChannels(id).Session { 383 registered = true 384 // In the background do... 385 go func() { 386 // A send of a `LoggedOut` RPC 387 _ = (keybase1.NotifySessionClient{ 388 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 389 }).LoggedOut(ctx) 390 }() 391 } 392 desc := "<nil>" 393 if d != nil { 394 desc = fmt.Sprintf("%+v", *d) 395 } 396 n.G().Log.CDebugf(ctx, "| NotifyRouter#HandleLogout: client %s (sent=%v)", desc, registered) 397 return true 398 }) 399 400 n.runListeners(func(listener NotifyListener) { 401 listener.Logout() 402 }) 403 } 404 405 // HandleLogin is called when a user logs in. 406 func (n *NotifyRouter) HandleLogin(ctx context.Context, u string) { 407 if n == nil { 408 return 409 } 410 n.G().Log.CDebugf(ctx, "+ Sending login notification for user %q", u) 411 n.SendLogin(ctx, u, false) 412 } 413 414 // HandleSignup is called when a user is signed up. It will broadcast a loggedIn 415 // notification with a flag to signify this was because of a signup. 416 func (n *NotifyRouter) HandleSignup(ctx context.Context, u string) { 417 if n == nil { 418 return 419 } 420 n.G().Log.CDebugf(ctx, "+ Sending login notification for signup, as user %q", u) 421 n.SendLogin(ctx, u, true) 422 } 423 424 // SendLogin is called whenever a user logs in. It will broadcast 425 // the message to all connections who care about such a message. 426 func (n *NotifyRouter) SendLogin(ctx context.Context, u string, signedUp bool) { 427 if n == nil { 428 return 429 } 430 n.G().Log.CDebugf(ctx, "+ Sending login notification, as user %q, signedUp %t", u, signedUp) 431 // For all connections we currently have open... 432 ctx = CopyTagsToBackground(ctx) 433 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 434 // If the connection wants the `Session` notification type 435 if n.getNotificationChannels(id).Session { 436 // In the background do... 437 go func() { 438 // A send of a `LoggedIn` RPC 439 _ = (keybase1.NotifySessionClient{ 440 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 441 }).LoggedIn(ctx, keybase1.LoggedInArg{ 442 Username: u, 443 SignedUp: signedUp, 444 }) 445 }() 446 } 447 return true 448 }) 449 450 n.runListeners(func(listener NotifyListener) { 451 listener.Login(u) 452 }) 453 n.G().Log.CDebugf(ctx, "- Login notification sent") 454 } 455 456 // ClientOutOfDate is called whenever the API server tells us our client is out 457 // of date. (This is done by adding special headers to every API response that 458 // an out-of-date client makes.) 459 func (n *NotifyRouter) HandleClientOutOfDate(upgradeTo, upgradeURI, upgradeMsg string) { 460 if n == nil { 461 return 462 } 463 n.G().Log.Debug("+ Sending client-out-of-date notification") 464 // For all connections we currently have open... 465 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 466 // If the connection wants the `Session` notification type 467 if n.getNotificationChannels(id).Session { 468 // In the background do... 469 go func() { 470 // A send of a `ClientOutOfDate` RPC 471 _ = (keybase1.NotifySessionClient{ 472 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 473 }).ClientOutOfDate(context.Background(), keybase1.ClientOutOfDateArg{ 474 UpgradeTo: upgradeTo, 475 UpgradeURI: upgradeURI, 476 UpgradeMsg: upgradeMsg, 477 }) 478 }() 479 } 480 return true 481 }) 482 n.runListeners(func(listener NotifyListener) { 483 listener.ClientOutOfDate(upgradeTo, upgradeURI, upgradeMsg) 484 }) 485 n.G().Log.Debug("- client-out-of-date notification sent") 486 } 487 488 // HandleUserChanged is called whenever we know that a given user has 489 // changed (and must be cache-busted). It will broadcast the messages 490 // to all curious listeners. NOTE: we now only do this for the current logged in user 491 func (n *NotifyRouter) HandleUserChanged(mctx MetaContext, uid keybase1.UID, reason string) { 492 if !mctx.G().GetMyUID().Equal(uid) { 493 // don't send these for anyone but the current logged in user, no one cares about anything 494 // about other users 495 return 496 } 497 mctx.Debug("Sending UserChanged notification %v '%v')", uid, reason) 498 if n == nil { 499 return 500 } 501 // For all connections we currently have open... 502 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 503 // If the connection wants the `Users` notification type 504 if n.getNotificationChannels(id).Users { 505 // In the background do... 506 go func() { 507 // A send of a `UserChanged` RPC with the user's UID 508 _ = (keybase1.NotifyUsersClient{ 509 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(mctx.G()), nil), 510 }).UserChanged(context.Background(), uid) 511 }() 512 } 513 return true 514 }) 515 n.runListeners(func(listener NotifyListener) { 516 listener.UserChanged(uid) 517 }) 518 } 519 520 // HandleTrackingChanged is called whenever we have a new tracking or 521 // untracking chain link related to a given user. It will broadcast the 522 // messages to all curious listeners. 523 // isTracking is set to true if current user is tracking uid. 524 func (n *NotifyRouter) HandleTrackingChanged(uid keybase1.UID, username NormalizedUsername, isTracking bool) { 525 if n == nil { 526 return 527 } 528 arg := keybase1.TrackingChangedArg{ 529 Uid: uid, 530 Username: username.String(), 531 IsTracking: isTracking, 532 } 533 // For all connections we currently have open... 534 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 535 // If the connection wants the `Tracking` notification type 536 if n.getNotificationChannels(id).Tracking { 537 // In the background do... 538 go func() { 539 // A send of a `TrackingChanged` RPC with the user's UID 540 _ = (keybase1.NotifyTrackingClient{ 541 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 542 }).TrackingChanged(context.Background(), arg) 543 }() 544 } 545 return true 546 }) 547 n.runListeners(func(listener NotifyListener) { 548 listener.TrackingChanged(uid, username) 549 }) 550 } 551 552 func (n *NotifyRouter) HandleWebOfTrustChanged(username string) { 553 if n == nil { 554 return 555 } 556 // For all connections we currently have open... 557 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 558 // If the connection wants the notification type 559 if n.getNotificationChannels(id).Tracking { 560 // In the background do... 561 go func() { 562 // A send of a `WebOfTrustChanged` RPC with the user's username 563 _ = (keybase1.NotifyUsersClient{ 564 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 565 }).WebOfTrustChanged(context.Background(), username) 566 }() 567 } 568 return true 569 }) 570 n.runListeners(func(listener NotifyListener) { 571 listener.WebOfTrustChanged(username) 572 }) 573 } 574 575 func (n *NotifyRouter) HandleTrackingInfo(arg keybase1.TrackingInfoArg) { 576 if n == nil { 577 return 578 } 579 // For all connections we currently have open... 580 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 581 // If the connection wants the `Tracking` notification type 582 if n.getNotificationChannels(id).Tracking { 583 // In the background do... 584 go func() { 585 // A send of a `TrackingInfo` RPC with the user's UID 586 _ = (keybase1.NotifyTrackingClient{ 587 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 588 }).TrackingInfo(context.Background(), arg) 589 }() 590 } 591 return true 592 }) 593 n.runListeners(func(listener NotifyListener) { 594 listener.TrackingInfo(arg.Uid, arg.Followers, arg.Followees) 595 }) 596 } 597 598 // HandleBadgeState is called whenever the badge state changes 599 // It will broadcast the messages to all curious listeners. 600 func (n *NotifyRouter) HandleBadgeState(badgeState keybase1.BadgeState) { 601 if n == nil { 602 return 603 } 604 n.G().Log.Debug("Sending BadgeState notification") 605 // For all connections we currently have open... 606 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 607 // If the connection wants the `Badges` notification type 608 if n.getNotificationChannels(id).Badges { 609 // In the background do... 610 go func() { 611 // A send of a `BadgeState` RPC with the badge state 612 _ = (keybase1.NotifyBadgesClient{ 613 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 614 }).BadgeState(context.Background(), badgeState) 615 }() 616 } 617 return true 618 }) 619 n.runListeners(func(listener NotifyListener) { 620 listener.BadgeState(badgeState) 621 }) 622 } 623 624 // HandleFSOnlineStatusChanged is called when KBFS's online status changes. It 625 // will broadcast the messages to all curious listeners. 626 func (n *NotifyRouter) HandleFSOnlineStatusChanged(online bool) { 627 if n == nil { 628 return 629 } 630 // For all connections we currently have open... 631 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 632 // If the connection wants the `kbfs` notification type 633 if n.getNotificationChannels(id).Kbfs { 634 // In the background do... 635 go func() { 636 // A send of a `FSOnlineStatusChanged` RPC with the 637 // notification 638 _ = (keybase1.NotifyFSClient{ 639 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 640 }).FSOnlineStatusChanged(context.Background(), online) 641 }() 642 } 643 return true 644 }) 645 n.runListeners(func(listener NotifyListener) { 646 listener.FSOnlineStatusChanged(online) 647 }) 648 } 649 650 // HandleFSOverallSyncStatusChanged is called when the overall sync status 651 // changes. It will broadcast the messages to all curious listeners. 652 func (n *NotifyRouter) HandleFSOverallSyncStatusChanged(status keybase1.FolderSyncStatus) { 653 if n == nil { 654 return 655 } 656 // For all connections we currently have open... 657 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 658 // If the connection wants the `kbfs` notification type 659 if n.getNotificationChannels(id).Kbfs { 660 // In the background do... 661 go func() { 662 // A send of a `FSOnlineStatusChanged` RPC with the 663 // notification 664 _ = (keybase1.NotifyFSClient{ 665 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 666 }).FSOverallSyncStatusChanged(context.Background(), status) 667 }() 668 } 669 return true 670 }) 671 n.runListeners(func(listener NotifyListener) { 672 listener.FSOverallSyncStatusChanged(status) 673 }) 674 } 675 676 // HandleFSFavoritesChanged is called when the overall sync status 677 // changes. It will broadcast the messages to all curious listeners. 678 func (n *NotifyRouter) HandleFSFavoritesChanged() { 679 if n == nil { 680 return 681 } 682 // For all connections we currently have open... 683 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 684 // If the connection wants the `kbfs` notification type 685 if n.getNotificationChannels(id).Kbfs { 686 // In the background do... 687 go func() { 688 // A send of a `FSFavoritesChanged` RPC with the 689 // notification 690 _ = (keybase1.NotifyFSClient{ 691 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 692 }).FSFavoritesChanged(context.Background()) 693 }() 694 } 695 return true 696 }) 697 n.runListeners(func(listener NotifyListener) { 698 listener.FSFavoritesChanged() 699 }) 700 } 701 702 // HandleFSActivity is called for any KBFS notification. It will broadcast the messages 703 // to all curious listeners. 704 func (n *NotifyRouter) HandleFSActivity(activity keybase1.FSNotification) { 705 if n == nil { 706 return 707 } 708 // For all connections we currently have open... 709 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 710 // If the connection wants the `Kbfsdesktop` notification type 711 if n.getNotificationChannels(id).Kbfsdesktop { 712 // In the background do... 713 go func() { 714 // A send of a `FSActivity` RPC with the notification 715 _ = (keybase1.NotifyFSClient{ 716 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 717 }).FSActivity(context.Background(), activity) 718 }() 719 } 720 return true 721 }) 722 n.runListeners(func(listener NotifyListener) { 723 listener.FSActivity(activity) 724 }) 725 } 726 727 // HandleFSPathUpdated is called for any path update notification. It 728 // will broadcast the messages to all curious listeners. 729 func (n *NotifyRouter) HandleFSPathUpdated(path string) { 730 if n == nil { 731 return 732 } 733 // For all connections we currently have open... 734 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 735 // If the connection wants the `Kbfs` notification type 736 if n.getNotificationChannels(id).Kbfs { 737 // In the background do... 738 go func() { 739 // A send of a `FSPathUpdated` RPC with the notification 740 _ = (keybase1.NotifyFSClient{ 741 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 742 }).FSPathUpdated(context.Background(), path) 743 }() 744 } 745 return true 746 }) 747 748 n.runListeners(func(listener NotifyListener) { 749 listener.FSPathUpdated(path) 750 }) 751 } 752 753 // HandleFSEditListResponse is called for KBFS edit list response notifications. 754 func (n *NotifyRouter) HandleFSEditListResponse(ctx context.Context, arg keybase1.FSEditListArg) { 755 if n == nil { 756 return 757 } 758 759 // We have to make sure the context survives until all subsequent 760 // RPCs launched in this method are done. So we wait until 761 // the last completes before returning. 762 var wg sync.WaitGroup 763 764 // For all connections we currently have open... 765 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 766 // If the connection wants the `Kbfslegacy` notification type 767 if n.getNotificationChannels(id).Kbfslegacy { 768 // In the background do... 769 wg.Add(1) 770 go func() { 771 // A send of a `FSEditListResponse` RPC with the notification 772 _ = (keybase1.NotifyFSClient{ 773 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 774 }).FSEditListResponse(context.Background(), keybase1.FSEditListResponseArg(arg)) 775 wg.Done() 776 }() 777 } 778 return true 779 }) 780 wg.Wait() 781 782 n.runListeners(func(listener NotifyListener) { 783 listener.FSEditListResponse(arg) 784 }) 785 } 786 787 // HandleFSEditListRequest is called for KBFS edit list request notifications. 788 func (n *NotifyRouter) HandleFSEditListRequest(ctx context.Context, arg keybase1.FSEditListRequest) { 789 if n == nil { 790 return 791 } 792 793 // See above 794 var wg sync.WaitGroup 795 796 // For all connections we currently have open... 797 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 798 // If the connection wants the `Kbfslegacy` notification type 799 if n.getNotificationChannels(id).Kbfslegacy { 800 wg.Add(1) 801 // In the background do... 802 go func() { 803 // A send of a `FSEditListRequest` RPC with the notification 804 _ = (keybase1.NotifyFSRequestClient{ 805 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 806 }).FSEditListRequest(context.Background(), arg) 807 wg.Done() 808 }() 809 } 810 return true 811 }) 812 813 wg.Wait() 814 815 n.runListeners(func(listener NotifyListener) { 816 listener.FSEditListRequest(arg) 817 }) 818 } 819 820 // HandleFSSyncStatus is called for KBFS sync status notifications. 821 func (n *NotifyRouter) HandleFSSyncStatus(ctx context.Context, arg keybase1.FSSyncStatusArg) { 822 if n == nil { 823 return 824 } 825 // For all connections we currently have open... 826 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 827 // If the connection wants the `Kbfslegacy` notification type 828 if n.getNotificationChannels(id).Kbfslegacy { 829 // In the background do... 830 go func() { 831 // A send of a `FSSyncStatusResponse` RPC with the notification 832 _ = (keybase1.NotifyFSClient{ 833 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 834 }).FSSyncStatusResponse(context.Background(), keybase1.FSSyncStatusResponseArg(arg)) 835 }() 836 } 837 return true 838 }) 839 840 n.runListeners(func(listener NotifyListener) { 841 listener.FSSyncStatusResponse(arg) 842 }) 843 } 844 845 // HandleFSSyncEvent is called for KBFS sync event notifications. 846 func (n *NotifyRouter) HandleFSSyncEvent(ctx context.Context, arg keybase1.FSPathSyncStatus) { 847 if n == nil { 848 return 849 } 850 // For all connections we currently have open... 851 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 852 // If the connection wants the `Kbfs` notification type 853 if n.getNotificationChannels(id).Kbfs { 854 // In the background do... 855 go func() { 856 // A send of a `FSSyncActivity` RPC with the notification 857 _ = (keybase1.NotifyFSClient{ 858 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 859 }).FSSyncActivity(context.Background(), arg) 860 }() 861 } 862 return true 863 }) 864 n.runListeners(func(listener NotifyListener) { 865 listener.FSSyncEvent(arg) 866 }) 867 } 868 869 // HandleFavoritesChanged is called whenever the kbfs favorites change 870 // for a user (and caches should be invalidated). It will broadcast the 871 // messages to all curious listeners. 872 func (n *NotifyRouter) HandleFavoritesChanged(uid keybase1.UID) { 873 if n == nil { 874 return 875 } 876 877 n.G().Log.Debug("+ Sending favorites changed notification") 878 // For all connections we currently have open... 879 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 880 // If the connection wants the `Favorites` notification type 881 if n.getNotificationChannels(id).Favorites { 882 // In the background do... 883 go func() { 884 // A send of a `FavoritesChanged` RPC with the user's UID 885 _ = (keybase1.NotifyFavoritesClient{ 886 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 887 }).FavoritesChanged(context.Background(), uid) 888 }() 889 } 890 return true 891 }) 892 893 n.runListeners(func(listener NotifyListener) { 894 listener.FavoritesChanged(uid) 895 }) 896 n.G().Log.Debug("- Sent favorites changed notification") 897 } 898 899 func (n *NotifyRouter) HandleFSSubscriptionNotify(arg keybase1.FSSubscriptionNotifyArg) { 900 if n == nil { 901 return 902 } 903 // For all connections we currently have open... 904 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 905 // If the connection wants the `Kbfs` notification type 906 if n.getNotificationChannels(id).Kbfssubscription { 907 // In the background do... 908 go func() { 909 // A send of a `FSSyncActivity` RPC with the notification 910 _ = (keybase1.NotifyFSClient{ 911 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 912 }).FSSubscriptionNotify(context.Background(), arg) 913 }() 914 } 915 return true 916 }) 917 n.runListeners(func(listener NotifyListener) { 918 listener.FSSubscriptionNotify(arg) 919 }) 920 } 921 922 func (n *NotifyRouter) HandleFSSubscriptionNotifyPath(arg keybase1.FSSubscriptionNotifyPathArg) { 923 if n == nil { 924 return 925 } 926 // For all connections we currently have open... 927 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 928 // If the connection wants the `Kbfs` notification type 929 if n.getNotificationChannels(id).Kbfssubscription { 930 // In the background do... 931 go func() { 932 // A send of a `FSSyncActivity` RPC with the notification 933 _ = (keybase1.NotifyFSClient{ 934 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 935 }).FSSubscriptionNotifyPath(context.Background(), arg) 936 }() 937 } 938 return true 939 }) 940 n.runListeners(func(listener NotifyListener) { 941 listener.FSSubscriptionNotifyPath(arg) 942 }) 943 } 944 945 func (n *NotifyRouter) HandleSimpleFSArchiveStatusChanged(ctx context.Context, status keybase1.SimpleFSArchiveStatus) { 946 if n == nil { 947 return 948 } 949 // For all connections we currently have open... 950 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 951 // If the connection wants the `Kbfs` notification type 952 if n.getNotificationChannels(id).Notifysimplefs { // In the background do... 953 go func() { 954 _ = (keybase1.NotifySimpleFSClient{ 955 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 956 }).SimpleFSArchiveStatusChanged(context.Background(), status) 957 }() 958 } 959 return true 960 }) 961 n.runListeners(func(listener NotifyListener) { 962 listener.SimpleFSArchiveStatusChanged(status) 963 }) 964 } 965 966 // HandleDeviceCloneNotification is called when a run of the device clone status update 967 // finds a newly-added, possible clone. It will broadcast the messages to all curious listeners. 968 func (n *NotifyRouter) HandleDeviceCloneNotification(newClones int) { 969 if n == nil { 970 return 971 } 972 973 n.G().Log.Debug("+ Sending device clone notification") 974 // For all connections we currently have open... 975 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 976 // If the connection wants the `Deviceclone` notification type 977 if n.getNotificationChannels(id).Deviceclone { 978 // In the background do... 979 go func() { 980 // A send of a `DeviceCloneCountChanged` RPC with the number of newly discovered clones 981 _ = (keybase1.NotifyDeviceCloneClient{ 982 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 983 }).DeviceCloneCountChanged(context.Background(), newClones) 984 }() 985 } 986 return true 987 }) 988 989 n.runListeners(func(listener NotifyListener) { 990 listener.DeviceCloneCountChanged(newClones) 991 }) 992 n.G().Log.Debug("- Sent device clone notification") 993 } 994 995 // canSkipNotification checks if the notification can be ignored and the given 996 // connection allows skips. 997 func (n *NotifyRouter) canSkipNotif(id ConnectionID, canSkip bool) bool { 998 return canSkip && n.getNotificationChannels(id).AllowChatNotifySkips 999 } 1000 1001 func (n *NotifyRouter) shouldSendChatNotification(id ConnectionID, topicType chat1.TopicType) bool { 1002 switch topicType { 1003 case chat1.TopicType_CHAT: 1004 return n.getNotificationChannels(id).Chat 1005 case chat1.TopicType_DEV: 1006 return n.getNotificationChannels(id).Chatdev 1007 case chat1.TopicType_KBFSFILEEDIT: 1008 return n.getNotificationChannels(id).Chatkbfsedits 1009 case chat1.TopicType_EMOJI: 1010 return n.getNotificationChannels(id).Chatemoji 1011 case chat1.TopicType_EMOJICROSS: 1012 return n.getNotificationChannels(id).Chatemojicross 1013 case chat1.TopicType_NONE: 1014 return n.getNotificationChannels(id).Chat || 1015 n.getNotificationChannels(id).Chatdev || 1016 n.getNotificationChannels(id).Chatkbfsedits || 1017 n.getNotificationChannels(id).Chatemoji || 1018 n.getNotificationChannels(id).Chatemojicross 1019 } 1020 return false 1021 } 1022 1023 func (n *NotifyRouter) HandleNewChatActivity(ctx context.Context, uid keybase1.UID, 1024 topicType chat1.TopicType, activity *chat1.ChatActivity, source chat1.ChatActivitySource, canSkip bool) { 1025 if n == nil { 1026 return 1027 } 1028 var wg sync.WaitGroup 1029 n.G().Log.CDebugf(ctx, "+ Sending NewChatActivity %v notification", source) 1030 // For all connections we currently have open... 1031 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1032 // If the connection wants the `Chat` notification type 1033 if n.shouldSendChatNotification(id, topicType) && !n.canSkipNotif(id, canSkip) { 1034 wg.Add(1) 1035 // In the background do... 1036 go func() { 1037 // A send of a `NewChatActivity` RPC with the user's UID 1038 _ = (chat1.NotifyChatClient{ 1039 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1040 }).NewChatActivity(context.Background(), chat1.NewChatActivityArg{ 1041 Uid: uid, 1042 Activity: *activity, 1043 Source: source, 1044 }) 1045 wg.Done() 1046 }() 1047 } 1048 return true 1049 }) 1050 wg.Wait() 1051 1052 n.runListeners(func(listener NotifyListener) { 1053 listener.NewChatActivity(uid, *activity, source) 1054 }) 1055 n.G().Log.CDebugf(ctx, "- Sent NewChatActivity notification") 1056 } 1057 1058 func (n *NotifyRouter) HandleChatIdentifyUpdate(ctx context.Context, update keybase1.CanonicalTLFNameAndIDWithBreaks) { 1059 if n == nil { 1060 return 1061 } 1062 var wg sync.WaitGroup 1063 n.G().Log.CDebugf(ctx, "+ Sending ChatIdentifyUpdate notification") 1064 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1065 if n.shouldSendChatNotification(id, chat1.TopicType_CHAT) { 1066 wg.Add(1) 1067 go func() { 1068 _ = (chat1.NotifyChatClient{ 1069 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1070 }).ChatIdentifyUpdate(context.Background(), update) 1071 wg.Done() 1072 }() 1073 } 1074 return true 1075 }) 1076 wg.Wait() 1077 1078 n.runListeners(func(listener NotifyListener) { 1079 listener.ChatIdentifyUpdate(update) 1080 }) 1081 n.G().Log.CDebugf(ctx, "- Sent ChatIdentifyUpdate notification") 1082 } 1083 1084 func (n *NotifyRouter) HandleChatTLFFinalize(ctx context.Context, uid keybase1.UID, 1085 convID chat1.ConversationID, topicType chat1.TopicType, finalizeInfo chat1.ConversationFinalizeInfo, 1086 conv *chat1.InboxUIItem) { 1087 if n == nil { 1088 return 1089 } 1090 var wg sync.WaitGroup 1091 n.G().Log.CDebugf(ctx, "+ Sending ChatTLFFinalize notification") 1092 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1093 if n.shouldSendChatNotification(id, topicType) { 1094 wg.Add(1) 1095 go func() { 1096 _ = (chat1.NotifyChatClient{ 1097 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1098 }).ChatTLFFinalize(context.Background(), chat1.ChatTLFFinalizeArg{ 1099 Uid: uid, 1100 ConvID: convID, 1101 FinalizeInfo: finalizeInfo, 1102 Conv: conv, 1103 }) 1104 wg.Done() 1105 }() 1106 } 1107 return true 1108 }) 1109 wg.Wait() 1110 1111 n.runListeners(func(listener NotifyListener) { 1112 listener.ChatTLFFinalize(uid, convID, finalizeInfo) 1113 }) 1114 n.G().Log.CDebugf(ctx, "- Sent ChatTLFFinalize notification") 1115 } 1116 1117 func (n *NotifyRouter) HandleChatTLFResolve(ctx context.Context, uid keybase1.UID, 1118 convID chat1.ConversationID, topicType chat1.TopicType, resolveInfo chat1.ConversationResolveInfo) { 1119 if n == nil { 1120 return 1121 } 1122 var wg sync.WaitGroup 1123 n.G().Log.CDebugf(ctx, "+ Sending ChatTLFResolve notification") 1124 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1125 if n.shouldSendChatNotification(id, topicType) { 1126 wg.Add(1) 1127 go func() { 1128 _ = (chat1.NotifyChatClient{ 1129 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1130 }).ChatTLFResolve(context.Background(), chat1.ChatTLFResolveArg{ 1131 Uid: uid, 1132 ConvID: convID, 1133 ResolveInfo: resolveInfo, 1134 }) 1135 wg.Done() 1136 }() 1137 } 1138 return true 1139 }) 1140 wg.Wait() 1141 1142 n.runListeners(func(listener NotifyListener) { 1143 listener.ChatTLFResolve(uid, convID, resolveInfo) 1144 }) 1145 n.G().Log.CDebugf(ctx, "- Sent ChatTLFResolve notification") 1146 } 1147 1148 func (n *NotifyRouter) HandleChatInboxStale(ctx context.Context, uid keybase1.UID) { 1149 if n == nil { 1150 return 1151 } 1152 var wg sync.WaitGroup 1153 n.G().Log.CDebugf(ctx, "+ Sending ChatInboxStale notification") 1154 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1155 if n.shouldSendChatNotification(id, chat1.TopicType_NONE) { 1156 wg.Add(1) 1157 go func() { 1158 _ = (chat1.NotifyChatClient{ 1159 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1160 }).ChatInboxStale(context.Background(), uid) 1161 wg.Done() 1162 }() 1163 } 1164 return true 1165 }) 1166 wg.Wait() 1167 1168 n.runListeners(func(listener NotifyListener) { 1169 listener.ChatInboxStale(uid) 1170 }) 1171 n.G().Log.CDebugf(ctx, "- Sent ChatInboxStale notification") 1172 } 1173 1174 func (n *NotifyRouter) HandleChatThreadsStale(ctx context.Context, uid keybase1.UID, 1175 updates []chat1.ConversationStaleUpdate) { 1176 if n == nil { 1177 return 1178 } 1179 var wg sync.WaitGroup 1180 n.G().Log.CDebugf(ctx, "+ Sending ChatThreadsStale notification") 1181 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1182 if n.shouldSendChatNotification(id, chat1.TopicType_NONE) { 1183 wg.Add(1) 1184 go func() { 1185 _ = (chat1.NotifyChatClient{ 1186 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1187 }).ChatThreadsStale(context.Background(), chat1.ChatThreadsStaleArg{ 1188 Uid: uid, 1189 Updates: updates, 1190 }) 1191 wg.Done() 1192 }() 1193 } 1194 return true 1195 }) 1196 wg.Wait() 1197 1198 n.runListeners(func(listener NotifyListener) { 1199 listener.ChatThreadsStale(uid, updates) 1200 }) 1201 n.G().Log.CDebugf(ctx, "- Sent ChatThreadsStale notification") 1202 } 1203 1204 func (n *NotifyRouter) HandleChatInboxSynced(ctx context.Context, uid keybase1.UID, 1205 topicType chat1.TopicType, syncRes chat1.ChatSyncResult) { 1206 if n == nil { 1207 return 1208 } 1209 var wg sync.WaitGroup 1210 typ, _ := syncRes.SyncType() 1211 n.G().Log.CDebugf(ctx, "+ Sending ChatInboxSynced notification: syncTyp: %v topicType: %v", typ, topicType) 1212 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1213 if n.shouldSendChatNotification(id, topicType) { 1214 wg.Add(1) 1215 go func() { 1216 _ = (chat1.NotifyChatClient{ 1217 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1218 }).ChatInboxSynced(context.Background(), chat1.ChatInboxSyncedArg{ 1219 Uid: uid, 1220 SyncRes: syncRes, 1221 }) 1222 wg.Done() 1223 }() 1224 } 1225 return true 1226 }) 1227 wg.Wait() 1228 1229 n.runListeners(func(listener NotifyListener) { 1230 listener.ChatInboxSynced(uid, topicType, syncRes) 1231 }) 1232 n.G().Log.CDebugf(ctx, "- Sent ChatInboxSynced notification") 1233 } 1234 1235 func (n *NotifyRouter) HandleChatInboxSyncStarted(ctx context.Context, uid keybase1.UID) { 1236 if n == nil { 1237 return 1238 } 1239 var wg sync.WaitGroup 1240 n.G().Log.CDebugf(ctx, "+ Sending ChatInboxSyncStarted notification") 1241 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1242 if n.shouldSendChatNotification(id, chat1.TopicType_NONE) { 1243 wg.Add(1) 1244 go func() { 1245 _ = (chat1.NotifyChatClient{ 1246 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1247 }).ChatInboxSyncStarted(context.Background(), uid) 1248 wg.Done() 1249 }() 1250 } 1251 return true 1252 }) 1253 wg.Wait() 1254 1255 n.runListeners(func(listener NotifyListener) { 1256 listener.ChatInboxSyncStarted(uid) 1257 }) 1258 n.G().Log.CDebugf(ctx, "- Sent ChatInboxSyncStarted notification") 1259 } 1260 1261 func (n *NotifyRouter) HandleChatTypingUpdate(ctx context.Context, updates []chat1.ConvTypingUpdate) { 1262 if n == nil { 1263 return 1264 } 1265 var wg sync.WaitGroup 1266 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1267 if n.shouldSendChatNotification(id, chat1.TopicType_CHAT) { 1268 wg.Add(1) 1269 go func() { 1270 _ = (chat1.NotifyChatClient{ 1271 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1272 }).ChatTypingUpdate(context.Background(), updates) 1273 wg.Done() 1274 }() 1275 } 1276 return true 1277 }) 1278 wg.Wait() 1279 1280 n.runListeners(func(listener NotifyListener) { 1281 listener.ChatTypingUpdate(updates) 1282 }) 1283 } 1284 1285 func (n *NotifyRouter) HandleChatJoinedConversation(ctx context.Context, uid keybase1.UID, 1286 convID chat1.ConversationID, topicType chat1.TopicType, conv *chat1.InboxUIItem) { 1287 if n == nil { 1288 return 1289 } 1290 var wg sync.WaitGroup 1291 n.G().Log.CDebugf(ctx, "+ Sending ChatJoinedConversation notification") 1292 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1293 if n.shouldSendChatNotification(id, topicType) { 1294 wg.Add(1) 1295 go func() { 1296 _ = (chat1.NotifyChatClient{ 1297 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1298 }).ChatJoinedConversation(context.Background(), chat1.ChatJoinedConversationArg{ 1299 Uid: uid, 1300 ConvID: convID, 1301 Conv: conv, 1302 }) 1303 wg.Done() 1304 }() 1305 } 1306 return true 1307 }) 1308 wg.Wait() 1309 1310 n.runListeners(func(listener NotifyListener) { 1311 listener.ChatJoinedConversation(uid, convID, conv) 1312 }) 1313 n.G().Log.CDebugf(ctx, "- Sent ChatJoinedConversation notification") 1314 } 1315 1316 func (n *NotifyRouter) HandleChatLeftConversation(ctx context.Context, uid keybase1.UID, 1317 convID chat1.ConversationID, topicType chat1.TopicType) { 1318 if n == nil { 1319 return 1320 } 1321 var wg sync.WaitGroup 1322 n.G().Log.CDebugf(ctx, "+ Sending ChatLeftConversation notification") 1323 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1324 if n.shouldSendChatNotification(id, topicType) { 1325 wg.Add(1) 1326 go func() { 1327 _ = (chat1.NotifyChatClient{ 1328 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1329 }).ChatLeftConversation(context.Background(), chat1.ChatLeftConversationArg{ 1330 Uid: uid, 1331 ConvID: convID, 1332 }) 1333 wg.Done() 1334 }() 1335 } 1336 return true 1337 }) 1338 wg.Wait() 1339 n.runListeners(func(listener NotifyListener) { 1340 listener.ChatLeftConversation(uid, convID) 1341 }) 1342 n.G().Log.CDebugf(ctx, "- Sent ChatLeftConversation notification") 1343 } 1344 1345 func (n *NotifyRouter) HandleChatResetConversation(ctx context.Context, uid keybase1.UID, 1346 convID chat1.ConversationID, topicType chat1.TopicType) { 1347 if n == nil { 1348 return 1349 } 1350 var wg sync.WaitGroup 1351 n.G().Log.CDebugf(ctx, "+ Sending ChatResetConversation notification") 1352 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1353 if n.shouldSendChatNotification(id, topicType) { 1354 wg.Add(1) 1355 go func() { 1356 _ = (chat1.NotifyChatClient{ 1357 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1358 }).ChatResetConversation(context.Background(), chat1.ChatResetConversationArg{ 1359 Uid: uid, 1360 ConvID: convID, 1361 }) 1362 wg.Done() 1363 }() 1364 } 1365 return true 1366 }) 1367 wg.Wait() 1368 1369 n.runListeners(func(listener NotifyListener) { 1370 listener.ChatResetConversation(uid, convID) 1371 }) 1372 n.G().Log.CDebugf(ctx, "- Sent ChatResetConversation notification") 1373 } 1374 1375 func (n *NotifyRouter) HandleChatKBFSToImpteamUpgrade(ctx context.Context, uid keybase1.UID, 1376 convID chat1.ConversationID, topicType chat1.TopicType) { 1377 if n == nil { 1378 return 1379 } 1380 var wg sync.WaitGroup 1381 n.G().Log.CDebugf(ctx, "+ Sending ChatKBFSToImpteamUpgrade notification") 1382 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1383 if n.shouldSendChatNotification(id, topicType) { 1384 wg.Add(1) 1385 go func() { 1386 _ = (chat1.NotifyChatClient{ 1387 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1388 }).ChatKBFSToImpteamUpgrade(context.Background(), chat1.ChatKBFSToImpteamUpgradeArg{ 1389 Uid: uid, 1390 ConvID: convID, 1391 }) 1392 wg.Done() 1393 }() 1394 } 1395 return true 1396 }) 1397 wg.Wait() 1398 1399 n.runListeners(func(listener NotifyListener) { 1400 listener.ChatKBFSToImpteamUpgrade(uid, convID) 1401 }) 1402 n.G().Log.CDebugf(ctx, "- Sent ChatKBFSToImpteamUpgrade notification") 1403 } 1404 1405 func (n *NotifyRouter) HandleChatAttachmentUploadStart(ctx context.Context, uid keybase1.UID, 1406 convID chat1.ConversationID, outboxID chat1.OutboxID) { 1407 if n == nil { 1408 return 1409 } 1410 var wg sync.WaitGroup 1411 n.G().Log.CDebugf(ctx, "+ Sending ChatAttachmentUploadStart notification") 1412 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1413 if n.getNotificationChannels(id).Chatattachments { 1414 wg.Add(1) 1415 go func() { 1416 _ = (chat1.NotifyChatClient{ 1417 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1418 }).ChatAttachmentUploadStart(context.Background(), chat1.ChatAttachmentUploadStartArg{ 1419 Uid: uid, 1420 ConvID: convID, 1421 OutboxID: outboxID, 1422 }) 1423 wg.Done() 1424 }() 1425 } 1426 return true 1427 }) 1428 wg.Wait() 1429 1430 n.runListeners(func(listener NotifyListener) { 1431 listener.ChatAttachmentUploadStart(uid, convID, outboxID) 1432 }) 1433 n.G().Log.CDebugf(ctx, "- Sent ChatAttachmentUploadStart notification") 1434 } 1435 1436 func (n *NotifyRouter) HandleChatAttachmentUploadProgress(ctx context.Context, uid keybase1.UID, 1437 convID chat1.ConversationID, outboxID chat1.OutboxID, bytesComplete, bytesTotal int64) { 1438 if n == nil { 1439 return 1440 } 1441 var wg sync.WaitGroup 1442 n.G().Log.CDebugf(ctx, "+ Sending ChatAttachmentUploadProgress notification") 1443 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1444 if n.getNotificationChannels(id).Chatattachments { 1445 wg.Add(1) 1446 go func() { 1447 _ = (chat1.NotifyChatClient{ 1448 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1449 }).ChatAttachmentUploadProgress(context.Background(), chat1.ChatAttachmentUploadProgressArg{ 1450 Uid: uid, 1451 ConvID: convID, 1452 OutboxID: outboxID, 1453 BytesComplete: bytesComplete, 1454 BytesTotal: bytesTotal, 1455 }) 1456 wg.Done() 1457 }() 1458 } 1459 return true 1460 }) 1461 wg.Wait() 1462 1463 n.runListeners(func(listener NotifyListener) { 1464 listener.ChatAttachmentUploadProgress(uid, convID, outboxID, bytesComplete, bytesTotal) 1465 }) 1466 n.G().Log.CDebugf(ctx, "- Sent ChatAttachmentUploadProgress notification") 1467 } 1468 1469 func (n *NotifyRouter) HandleChatAttachmentDownloadProgress(ctx context.Context, uid keybase1.UID, 1470 convID chat1.ConversationID, msgID chat1.MessageID, bytesComplete, bytesTotal int64) { 1471 if n == nil { 1472 return 1473 } 1474 var wg sync.WaitGroup 1475 n.G().Log.CDebugf(ctx, "+ Sending ChatAttachmentDownloadProgress notification") 1476 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1477 if n.getNotificationChannels(id).Chatattachments { 1478 wg.Add(1) 1479 go func() { 1480 _ = (chat1.NotifyChatClient{ 1481 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1482 }).ChatAttachmentDownloadProgress(context.Background(), chat1.ChatAttachmentDownloadProgressArg{ 1483 Uid: uid, 1484 ConvID: convID, 1485 MsgID: msgID, 1486 BytesComplete: bytesComplete, 1487 BytesTotal: bytesTotal, 1488 }) 1489 wg.Done() 1490 }() 1491 } 1492 return true 1493 }) 1494 wg.Wait() 1495 1496 n.runListeners(func(listener NotifyListener) { 1497 listener.ChatAttachmentDownloadProgress(uid, convID, msgID, bytesComplete, bytesTotal) 1498 }) 1499 n.G().Log.CDebugf(ctx, "- Sent ChatAttachmentDownloadProgress notification") 1500 } 1501 1502 func (n *NotifyRouter) HandleChatAttachmentDownloadComplete(ctx context.Context, uid keybase1.UID, 1503 convID chat1.ConversationID, msgID chat1.MessageID) { 1504 if n == nil { 1505 return 1506 } 1507 var wg sync.WaitGroup 1508 n.G().Log.CDebugf(ctx, "+ Sending ChatAttachmentDownloadComplete notification") 1509 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1510 if n.getNotificationChannels(id).Chatattachments { 1511 wg.Add(1) 1512 go func() { 1513 _ = (chat1.NotifyChatClient{ 1514 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1515 }).ChatAttachmentDownloadComplete(context.Background(), chat1.ChatAttachmentDownloadCompleteArg{ 1516 Uid: uid, 1517 ConvID: convID, 1518 MsgID: msgID, 1519 }) 1520 wg.Done() 1521 }() 1522 } 1523 return true 1524 }) 1525 wg.Wait() 1526 1527 n.runListeners(func(listener NotifyListener) { 1528 listener.ChatAttachmentDownloadComplete(uid, convID, msgID) 1529 }) 1530 n.G().Log.CDebugf(ctx, "- Sent ChatAttachmentDownloadComplete notification") 1531 } 1532 1533 func (n *NotifyRouter) HandleChatArchiveProgress(ctx context.Context, jobID chat1.ArchiveJobID, messagesComplete, messagesTotal int64) { 1534 if n == nil { 1535 return 1536 } 1537 var wg sync.WaitGroup 1538 n.G().Log.CDebugf(ctx, "+ Sending ChatArchiveProgress notification") 1539 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1540 if n.getNotificationChannels(id).Chatarchive { 1541 wg.Add(1) 1542 go func() { 1543 _ = (chat1.NotifyChatClient{ 1544 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1545 }).ChatArchiveProgress(context.Background(), chat1.ChatArchiveProgressArg{ 1546 JobID: jobID, 1547 MessagesComplete: messagesComplete, 1548 MessagesTotal: messagesTotal, 1549 }) 1550 wg.Done() 1551 }() 1552 } 1553 return true 1554 }) 1555 wg.Wait() 1556 1557 n.runListeners(func(listener NotifyListener) { 1558 listener.ChatArchiveProgress(jobID, messagesComplete, messagesTotal) 1559 }) 1560 n.G().Log.CDebugf(ctx, "- Sent ChatArchiveProgress notification") 1561 } 1562 1563 func (n *NotifyRouter) HandleChatArchiveComplete(ctx context.Context, jobID chat1.ArchiveJobID) { 1564 if n == nil { 1565 return 1566 } 1567 var wg sync.WaitGroup 1568 n.G().Log.CDebugf(ctx, "+ Sending ChatArchiveComplete notification") 1569 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1570 if n.getNotificationChannels(id).Chatarchive { 1571 wg.Add(1) 1572 go func() { 1573 _ = (chat1.NotifyChatClient{ 1574 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1575 }).ChatArchiveComplete(context.Background(), 1576 jobID, 1577 ) 1578 wg.Done() 1579 }() 1580 } 1581 return true 1582 }) 1583 wg.Wait() 1584 1585 n.runListeners(func(listener NotifyListener) { 1586 listener.ChatArchiveComplete(jobID) 1587 }) 1588 n.G().Log.CDebugf(ctx, "- Sent ChatArchiveComplete notification") 1589 } 1590 1591 func (n *NotifyRouter) HandleChatSetConvRetention(ctx context.Context, uid keybase1.UID, 1592 convID chat1.ConversationID, topicType chat1.TopicType, conv *chat1.InboxUIItem) { 1593 n.notifyChatCommon(ctx, "ChatSetConvRetention", topicType, 1594 func(ctx context.Context, cli *chat1.NotifyChatClient) { 1595 _ = cli.ChatSetConvRetention(ctx, chat1.ChatSetConvRetentionArg{ 1596 Uid: uid, 1597 ConvID: convID, 1598 Conv: conv, 1599 }) 1600 }, func(ctx context.Context, listener NotifyListener) { 1601 listener.ChatSetConvRetention(uid, convID) 1602 }) 1603 } 1604 1605 func (n *NotifyRouter) HandleChatSetTeamRetention(ctx context.Context, uid keybase1.UID, 1606 teamID keybase1.TeamID, topicType chat1.TopicType, convs []chat1.InboxUIItem) { 1607 n.notifyChatCommon(ctx, "ChatSetTeamRetention", topicType, 1608 func(ctx context.Context, cli *chat1.NotifyChatClient) { 1609 _ = cli.ChatSetTeamRetention(ctx, chat1.ChatSetTeamRetentionArg{ 1610 Uid: uid, 1611 TeamID: teamID, 1612 Convs: convs, 1613 }) 1614 }, func(ctx context.Context, listener NotifyListener) { 1615 listener.ChatSetTeamRetention(uid, teamID) 1616 }) 1617 } 1618 1619 func (n *NotifyRouter) HandleChatSetConvSettings(ctx context.Context, uid keybase1.UID, 1620 convID chat1.ConversationID, topicType chat1.TopicType, conv *chat1.InboxUIItem) { 1621 n.notifyChatCommon(ctx, "ChatSetConvSettings", topicType, 1622 func(ctx context.Context, cli *chat1.NotifyChatClient) { 1623 _ = cli.ChatSetConvSettings(ctx, chat1.ChatSetConvSettingsArg{ 1624 Uid: uid, 1625 ConvID: convID, 1626 Conv: conv, 1627 }) 1628 }, func(ctx context.Context, listener NotifyListener) { 1629 listener.ChatSetConvSettings(uid, convID) 1630 }) 1631 } 1632 1633 func (n *NotifyRouter) HandleChatSubteamRename(ctx context.Context, uid keybase1.UID, 1634 convIDs []chat1.ConversationID, topicType chat1.TopicType, convs []chat1.InboxUIItem) { 1635 n.notifyChatCommon(ctx, "ChatSubteamRename", topicType, 1636 func(ctx context.Context, cli *chat1.NotifyChatClient) { 1637 _ = cli.ChatSubteamRename(ctx, chat1.ChatSubteamRenameArg{ 1638 Uid: uid, 1639 Convs: convs, 1640 }) 1641 }, func(ctx context.Context, listener NotifyListener) { 1642 listener.ChatSubteamRename(uid, convIDs) 1643 }) 1644 } 1645 1646 func (n *NotifyRouter) HandleChatPromptUnfurl(ctx context.Context, uid keybase1.UID, 1647 convID chat1.ConversationID, msgID chat1.MessageID, domain string) { 1648 n.notifyChatCommon(ctx, "ChatPromptUnfurl", chat1.TopicType_CHAT, 1649 func(ctx context.Context, cli *chat1.NotifyChatClient) { 1650 _ = cli.ChatPromptUnfurl(ctx, chat1.ChatPromptUnfurlArg{ 1651 Uid: uid, 1652 ConvID: convID, 1653 MsgID: msgID, 1654 Domain: domain, 1655 }) 1656 }, func(ctx context.Context, listener NotifyListener) { 1657 listener.ChatPromptUnfurl(uid, convID, msgID, domain) 1658 }) 1659 } 1660 1661 func (n *NotifyRouter) HandleChatConvUpdate(ctx context.Context, uid keybase1.UID, 1662 convID chat1.ConversationID, topicType chat1.TopicType, conv *chat1.InboxUIItem) { 1663 n.notifyChatCommon(ctx, "ChatConvUpdate", topicType, 1664 func(ctx context.Context, cli *chat1.NotifyChatClient) { 1665 _ = cli.ChatConvUpdate(ctx, chat1.ChatConvUpdateArg{ 1666 Uid: uid, 1667 ConvID: convID, 1668 Conv: conv, 1669 }) 1670 }, func(ctx context.Context, listener NotifyListener) { 1671 listener.ChatConvUpdate(uid, convID) 1672 }) 1673 } 1674 1675 func (n *NotifyRouter) HandleChatWelcomeMessageLoaded(ctx context.Context, 1676 teamID keybase1.TeamID, message chat1.WelcomeMessageDisplay) { 1677 if n == nil { 1678 return 1679 } 1680 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1681 if n.getNotificationChannels(id).Chat { 1682 go func() { 1683 _ = (chat1.NotifyChatClient{ 1684 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1685 }).ChatWelcomeMessageLoaded(ctx, chat1.ChatWelcomeMessageLoadedArg{ 1686 TeamID: teamID, 1687 Message: message, 1688 }) 1689 }() 1690 } 1691 return true 1692 }) 1693 1694 n.runListeners(func(listener NotifyListener) { 1695 listener.ChatWelcomeMessageLoaded(teamID, message) 1696 }) 1697 } 1698 1699 func (n *NotifyRouter) HandleChatParticipantsInfo(ctx context.Context, 1700 participants map[chat1.ConvIDStr][]chat1.UIParticipant) { 1701 if n == nil { 1702 return 1703 } 1704 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1705 if n.getNotificationChannels(id).Chat { 1706 go func() { 1707 _ = (chat1.NotifyChatClient{ 1708 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1709 }).ChatParticipantsInfo(ctx, participants) 1710 }() 1711 } 1712 return true 1713 }) 1714 1715 n.runListeners(func(listener NotifyListener) { 1716 listener.ChatParticipantsInfo(participants) 1717 }) 1718 } 1719 1720 type notifyChatFn1 func(context.Context, *chat1.NotifyChatClient) 1721 type notifyChatFn2 func(context.Context, NotifyListener) 1722 1723 func (n *NotifyRouter) notifyChatCommon(ctx context.Context, debugLabel string, topicType chat1.TopicType, 1724 fn1 notifyChatFn1, fn2 notifyChatFn2) { 1725 if n == nil { 1726 return 1727 } 1728 var wg sync.WaitGroup 1729 n.G().Log.CDebugf(ctx, "+ Sending %v notification", debugLabel) 1730 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1731 if n.shouldSendChatNotification(id, topicType) { 1732 wg.Add(1) 1733 go func() { 1734 cli := &chat1.NotifyChatClient{ 1735 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1736 } 1737 fn1(context.Background(), cli) 1738 wg.Done() 1739 }() 1740 } 1741 return true 1742 }) 1743 wg.Wait() 1744 1745 n.runListeners(func(listener NotifyListener) { 1746 fn2(ctx, listener) 1747 }) 1748 n.G().Log.CDebugf(ctx, "- Sent %v notification", debugLabel) 1749 } 1750 1751 func (n *NotifyRouter) HandleWalletPaymentNotification(ctx context.Context, accountID stellar1.AccountID, paymentID stellar1.PaymentID) { 1752 if n == nil { 1753 return 1754 } 1755 n.G().Log.CDebugf(ctx, "+ Sending wallet PaymentNotification") 1756 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1757 // If the connection wants the `Wallet` notification type 1758 if n.getNotificationChannels(id).Wallet { 1759 // In the background do... 1760 go func() { 1761 arg := stellar1.PaymentNotificationArg{ 1762 AccountID: accountID, 1763 PaymentID: paymentID, 1764 } 1765 _ = (stellar1.NotifyClient{ 1766 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1767 }).PaymentNotification(context.Background(), arg) 1768 }() 1769 } 1770 return true 1771 }) 1772 1773 n.runListeners(func(listener NotifyListener) { 1774 listener.WalletPaymentNotification(accountID, paymentID) 1775 }) 1776 n.G().Log.CDebugf(ctx, "- Sent wallet PaymentNotification") 1777 } 1778 1779 func (n *NotifyRouter) HandleWalletPaymentStatusNotification(ctx context.Context, accountID stellar1.AccountID, paymentID stellar1.PaymentID) { 1780 if n == nil { 1781 return 1782 } 1783 n.G().Log.CDebugf(ctx, "+ Sending wallet PaymentStatusNotification") 1784 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1785 // If the connection wants the `Wallet` notification type 1786 if n.getNotificationChannels(id).Wallet { 1787 // In the background do... 1788 go func() { 1789 arg := stellar1.PaymentStatusNotificationArg{ 1790 AccountID: accountID, 1791 PaymentID: paymentID, 1792 } 1793 _ = (stellar1.NotifyClient{ 1794 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1795 }).PaymentStatusNotification(context.Background(), arg) 1796 }() 1797 } 1798 return true 1799 }) 1800 1801 n.runListeners(func(listener NotifyListener) { 1802 listener.WalletPaymentStatusNotification(accountID, paymentID) 1803 }) 1804 n.G().Log.CDebugf(ctx, "- Sent wallet PaymentStatusNotification") 1805 } 1806 1807 func (n *NotifyRouter) HandleWalletRequestStatusNotification(ctx context.Context, reqID stellar1.KeybaseRequestID) { 1808 if n == nil { 1809 return 1810 } 1811 n.G().Log.CDebugf(ctx, "+ Sending wallet RequestStatusNotification") 1812 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1813 // If the connection wants the `Wallet` notification type 1814 if n.getNotificationChannels(id).Wallet { 1815 // In the background do... 1816 go func() { 1817 _ = (stellar1.NotifyClient{ 1818 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1819 }).RequestStatusNotification(context.Background(), reqID) 1820 }() 1821 } 1822 return true 1823 }) 1824 1825 n.runListeners(func(listener NotifyListener) { 1826 listener.WalletRequestStatusNotification(reqID) 1827 }) 1828 n.G().Log.CDebugf(ctx, "- Sent wallet RequestStatusNotification") 1829 } 1830 1831 func (n *NotifyRouter) HandleWalletAccountDetailsUpdate(ctx context.Context, accountID stellar1.AccountID, account stellar1.WalletAccountLocal) { 1832 if n == nil { 1833 return 1834 } 1835 n.G().Log.CDebugf(ctx, "+ Sending wallet AccountDetailsUpdate") 1836 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1837 // If the connection wants the `Wallet` notification type 1838 if n.getNotificationChannels(id).Wallet { 1839 // In the background do... 1840 go func() { 1841 arg := stellar1.AccountDetailsUpdateArg{ 1842 AccountID: accountID, 1843 Account: account, 1844 } 1845 _ = (stellar1.NotifyClient{ 1846 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1847 }).AccountDetailsUpdate(context.Background(), arg) 1848 }() 1849 } 1850 return true 1851 }) 1852 1853 n.runListeners(func(listener NotifyListener) { 1854 listener.WalletAccountDetailsUpdate(accountID, account) 1855 }) 1856 n.G().Log.CDebugf(ctx, "- Sent wallet AccountDetailsUpdate") 1857 } 1858 1859 func (n *NotifyRouter) HandleWalletAccountsUpdate(ctx context.Context, accounts []stellar1.WalletAccountLocal) { 1860 if n == nil { 1861 return 1862 } 1863 n.G().Log.CDebugf(ctx, "+ Sending wallet AccountsUpdate") 1864 1865 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1866 // If the connection wants the `Wallet` notification type 1867 if n.getNotificationChannels(id).Wallet { 1868 // In the background do... 1869 go func() { 1870 _ = (stellar1.NotifyClient{ 1871 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1872 }).AccountsUpdate(context.Background(), accounts) 1873 }() 1874 } 1875 return true 1876 }) 1877 1878 n.runListeners(func(listener NotifyListener) { 1879 listener.WalletAccountsUpdate(accounts) 1880 }) 1881 n.G().Log.CDebugf(ctx, "- Sent wallet AccountsUpdate") 1882 } 1883 1884 func (n *NotifyRouter) HandleWalletPendingPaymentsUpdate(ctx context.Context, accountID stellar1.AccountID, pending []stellar1.PaymentOrErrorLocal) { 1885 if n == nil { 1886 return 1887 } 1888 n.G().Log.CDebugf(ctx, "+ Sending wallet PendingPaymentsUpdate") 1889 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1890 // If the connection wants the `Wallet` notification type 1891 if n.getNotificationChannels(id).Wallet { 1892 // In the background do... 1893 go func() { 1894 arg := stellar1.PendingPaymentsUpdateArg{ 1895 AccountID: accountID, 1896 Pending: pending, 1897 } 1898 _ = (stellar1.NotifyClient{ 1899 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1900 }).PendingPaymentsUpdate(context.Background(), arg) 1901 }() 1902 } 1903 return true 1904 }) 1905 1906 n.runListeners(func(listener NotifyListener) { 1907 listener.WalletPendingPaymentsUpdate(accountID, pending) 1908 }) 1909 n.G().Log.CDebugf(ctx, "- Sent wallet PendingPaymentsUpdate") 1910 } 1911 1912 func (n *NotifyRouter) HandleWalletRecentPaymentsUpdate(ctx context.Context, accountID stellar1.AccountID, firstPage stellar1.PaymentsPageLocal) { 1913 if n == nil { 1914 return 1915 } 1916 n.G().Log.CDebugf(ctx, "+ Sending wallet RecentPaymentsUpdate") 1917 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1918 // If the connection wants the `Wallet` notification type 1919 if n.getNotificationChannels(id).Wallet { 1920 // In the background do... 1921 go func() { 1922 arg := stellar1.RecentPaymentsUpdateArg{ 1923 AccountID: accountID, 1924 FirstPage: firstPage, 1925 } 1926 _ = (stellar1.NotifyClient{ 1927 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1928 }).RecentPaymentsUpdate(context.Background(), arg) 1929 }() 1930 } 1931 return true 1932 }) 1933 1934 n.runListeners(func(listener NotifyListener) { 1935 listener.WalletRecentPaymentsUpdate(accountID, firstPage) 1936 }) 1937 n.G().Log.CDebugf(ctx, "- Sent wallet RecentPaymentsUpdate") 1938 } 1939 1940 // HandlePaperKeyCached is called whenever a paper key is cached 1941 // in response to a rekey harassment. 1942 func (n *NotifyRouter) HandlePaperKeyCached(uid keybase1.UID, encKID keybase1.KID, sigKID keybase1.KID) { 1943 if n == nil { 1944 return 1945 } 1946 1947 n.G().Log.Debug("+ Sending paperkey cached notification") 1948 arg := keybase1.PaperKeyCachedArg{ 1949 Uid: uid, 1950 EncKID: encKID, 1951 SigKID: sigKID, 1952 } 1953 var wg sync.WaitGroup 1954 1955 // For all connections we currently have open... 1956 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1957 // If the connection wants the `Favorites` notification type 1958 if n.getNotificationChannels(id).Paperkeys { 1959 wg.Add(1) 1960 // In the background do... 1961 go func() { 1962 _ = (keybase1.NotifyPaperKeyClient{ 1963 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1964 }).PaperKeyCached(context.Background(), arg) 1965 wg.Done() 1966 }() 1967 } 1968 return true 1969 }) 1970 wg.Wait() 1971 1972 n.runListeners(func(listener NotifyListener) { 1973 listener.PaperKeyCached(uid, encKID, sigKID) 1974 }) 1975 n.G().Log.Debug("- Sent paperkey cached notification") 1976 } 1977 1978 // HandleKeyfamilyChanged is called whenever a user's keyfamily changes. 1979 func (n *NotifyRouter) HandleKeyfamilyChanged(uid keybase1.UID) { 1980 if n == nil { 1981 return 1982 } 1983 1984 n.G().Log.Debug("+ Sending keyfamily changed notification") 1985 // For all connections we currently have open... 1986 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 1987 // If the connection wants the `Favorites` notification type 1988 if n.getNotificationChannels(id).Keyfamily { 1989 // In the background do... 1990 go func() { 1991 _ = (keybase1.NotifyKeyfamilyClient{ 1992 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 1993 }).KeyfamilyChanged(context.Background(), uid) 1994 }() 1995 } 1996 return true 1997 }) 1998 1999 n.runListeners(func(listener NotifyListener) { 2000 listener.KeyfamilyChanged(uid) 2001 }) 2002 n.G().Log.Debug("- Sent keyfamily changed notification") 2003 } 2004 2005 // HandleServiceShutdown is called whenever the service shuts down. 2006 func (n *NotifyRouter) HandleServiceShutdown() { 2007 if n == nil { 2008 return 2009 } 2010 2011 n.G().Log.Debug("+ Sending service shutdown notification") 2012 2013 var wg sync.WaitGroup 2014 2015 // For all connections we currently have open... 2016 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2017 // If the connection wants the `Service` notification type 2018 if n.getNotificationChannels(id).Service { 2019 // In the background do... 2020 wg.Add(1) 2021 go func() { 2022 _ = (keybase1.NotifyServiceClient{ 2023 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2024 }).Shutdown(context.Background(), int(n.G().ExitCode)) 2025 wg.Done() 2026 }() 2027 } 2028 return true 2029 }) 2030 2031 done := make(chan struct{}) 2032 go func() { 2033 wg.Wait() 2034 close(done) 2035 }() 2036 2037 // timeout after 4s (launchd will SIGKILL after 5s) 2038 select { 2039 case <-done: 2040 n.G().Log.Debug("Finished sending service shutdown notifications") 2041 case <-time.After(4 * time.Second): 2042 n.G().Log.Warning("Timed out sending service shutdown notifications, proceeding to shutdown") 2043 } 2044 2045 n.G().Log.Debug("- Sent service shutdown notification") 2046 } 2047 2048 // HandleAppExit is called whenever an app exit command is issued 2049 func (n *NotifyRouter) HandleAppExit() { 2050 if n == nil { 2051 return 2052 } 2053 n.G().Log.Debug("+ Sending app exit notification") 2054 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2055 if n.getNotificationChannels(id).App { 2056 go func() { 2057 _ = (keybase1.NotifyAppClient{ 2058 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2059 }).Exit(context.Background()) 2060 }() 2061 } 2062 return true 2063 }) 2064 n.G().Log.Debug("- Sent app exit notification") 2065 } 2066 2067 // HandlePGPKeyInSecretStoreFile is called to notify a user that they have a PGP 2068 // key that is unlockable by a secret stored in a file in their home directory. 2069 func (n *NotifyRouter) HandlePGPKeyInSecretStoreFile() { 2070 n.G().Log.Debug("+ Sending pgpKeyInSecretStoreFile notification") 2071 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2072 if n.getNotificationChannels(id).PGP { 2073 go func() { 2074 _ = (keybase1.NotifyPGPClient{ 2075 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2076 }).PGPKeyInSecretStoreFile(context.Background()) 2077 }() 2078 } 2079 return true 2080 }) 2081 2082 n.runListeners(func(listener NotifyListener) { 2083 listener.PGPKeyInSecretStoreFile() 2084 }) 2085 n.G().Log.Debug("- Sent pgpKeyInSecretStoreFile notification") 2086 } 2087 2088 func (n *NotifyRouter) HandleReachability(r keybase1.Reachability) { 2089 n.G().Log.Debug("+ Sending reachability") 2090 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2091 if n.getNotificationChannels(id).Reachability { 2092 go func() { 2093 _ = (keybase1.ReachabilityClient{ 2094 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2095 }).ReachabilityChanged(context.Background(), r) 2096 }() 2097 } 2098 return true 2099 }) 2100 n.runListeners(func(listener NotifyListener) { 2101 listener.Reachability(r) 2102 }) 2103 n.G().Log.Debug("- Sent reachability") 2104 } 2105 2106 // teamID and teamName are not necessarily the same team 2107 func (n *NotifyRouter) HandleTeamChangedByBothKeys(ctx context.Context, 2108 teamID keybase1.TeamID, teamName string, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, 2109 latestHiddenSeqno keybase1.Seqno, latestOffchainSeqno keybase1.Seqno, source keybase1.TeamChangedSource) { 2110 2111 n.HandleTeamChangedByID(ctx, teamID, latestSeqno, implicitTeam, changes, latestHiddenSeqno, latestOffchainSeqno, source) 2112 n.HandleTeamChangedByName(ctx, teamName, latestSeqno, implicitTeam, changes, latestHiddenSeqno, latestOffchainSeqno, source) 2113 } 2114 2115 func (n *NotifyRouter) HandleTeamChangedByID(ctx context.Context, 2116 teamID keybase1.TeamID, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, 2117 latestHiddenSeqno keybase1.Seqno, latestOffchainSeqno keybase1.Seqno, source keybase1.TeamChangedSource) { 2118 2119 if n == nil { 2120 return 2121 } 2122 2123 arg := keybase1.TeamChangedByIDArg{ 2124 TeamID: teamID, 2125 LatestSeqno: latestSeqno, 2126 ImplicitTeam: implicitTeam, 2127 Changes: changes, 2128 LatestHiddenSeqno: latestHiddenSeqno, 2129 LatestOffchainSeqno: latestOffchainSeqno, 2130 Source: source, 2131 } 2132 2133 var wg sync.WaitGroup 2134 n.G().Log.CDebugf(ctx, "+ Sending TeamChangedByID notification (team:%v, seqno:%v, implicit:%v)", 2135 teamID, latestSeqno, implicitTeam) 2136 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2137 if n.getNotificationChannels(id).Team { 2138 wg.Add(1) 2139 go func() { 2140 _ = (keybase1.NotifyTeamClient{ 2141 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2142 }).TeamChangedByID(context.Background(), arg) 2143 wg.Done() 2144 }() 2145 } 2146 return true 2147 }) 2148 wg.Wait() 2149 2150 n.runListeners(func(listener NotifyListener) { 2151 listener.TeamChangedByID(teamID, latestSeqno, implicitTeam, changes, latestHiddenSeqno, source) 2152 }) 2153 n.G().Log.CDebugf(ctx, "- Sent TeamChangedByID notification") 2154 } 2155 2156 func (n *NotifyRouter) HandleTeamChangedByName(ctx context.Context, 2157 teamName string, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, 2158 latestHiddenSeqno keybase1.Seqno, latestOffchainSeqno keybase1.Seqno, source keybase1.TeamChangedSource) { 2159 2160 if n == nil { 2161 return 2162 } 2163 2164 arg := keybase1.TeamChangedByNameArg{ 2165 TeamName: teamName, 2166 LatestSeqno: latestSeqno, 2167 ImplicitTeam: implicitTeam, 2168 Changes: changes, 2169 LatestHiddenSeqno: latestHiddenSeqno, 2170 LatestOffchainSeqno: latestOffchainSeqno, 2171 Source: source, 2172 } 2173 2174 var wg sync.WaitGroup 2175 n.G().Log.CDebugf(ctx, "+ Sending TeamChangedByName notification (team:%v, seqno:%v, implicit:%v)", 2176 teamName, latestSeqno, implicitTeam) 2177 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2178 if n.getNotificationChannels(id).Team { 2179 wg.Add(1) 2180 go func() { 2181 _ = (keybase1.NotifyTeamClient{ 2182 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2183 }).TeamChangedByName(context.Background(), arg) 2184 wg.Done() 2185 }() 2186 } 2187 return true 2188 }) 2189 wg.Wait() 2190 2191 n.runListeners(func(listener NotifyListener) { 2192 listener.TeamChangedByName(teamName, latestSeqno, implicitTeam, changes, latestHiddenSeqno, source) 2193 }) 2194 n.G().Log.CDebugf(ctx, "- Sent TeamChanged notification") 2195 } 2196 2197 // TeamMetadataUpdateUnverified is called when a notification is received that 2198 // affects the teams tab root page. 2199 func (n *NotifyRouter) HandleTeamMetadataUpdate(ctx context.Context) { 2200 if n == nil { 2201 return 2202 } 2203 2204 n.G().Log.Debug("+ Sending TeamMetadataUpdate notification") 2205 // For all connections we currently have open... 2206 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2207 // If the connection wants the `Team` notifications 2208 if n.getNotificationChannels(id).Team { 2209 // In the background do... 2210 go func() { 2211 // A send of a `TeamListUnverifiedChanged` RPC 2212 _ = (keybase1.NotifyTeamClient{ 2213 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2214 }).TeamMetadataUpdate(context.Background()) 2215 }() 2216 } 2217 return true 2218 }) 2219 2220 n.runListeners(func(listener NotifyListener) { 2221 listener.TeamMetadataUpdate() 2222 }) 2223 n.G().Log.Debug("- Sent TeamMetadata notification") 2224 } 2225 2226 // HandleCanUserPerformChanged is called when a notification is received from gregor that 2227 // we think might be of interest to the UI, specifically the parts of the UI that update 2228 // permissions for a user in a team. 2229 func (n *NotifyRouter) HandleCanUserPerformChanged(ctx context.Context, teamName string) { 2230 if n == nil { 2231 return 2232 } 2233 2234 n.G().Log.Debug("+ Sending CanUserPerformChanged notification (team:%v)", teamName) 2235 // For all connections we currently have open... 2236 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2237 // If the connection wants the `Team` notification type 2238 if n.getNotificationChannels(id).Team { 2239 // In the background do... 2240 go func() { 2241 // A send of a `CanUserPerformChanged` RPC 2242 _ = (keybase1.NotifyCanUserPerformClient{ 2243 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2244 }).CanUserPerformChanged(context.Background(), teamName) 2245 }() 2246 } 2247 return true 2248 }) 2249 2250 n.runListeners(func(listener NotifyListener) { 2251 listener.CanUserPerformChanged(teamName) 2252 }) 2253 n.G().Log.Debug("- Sent CanUserPerformChanged notification (team:%v)", teamName) 2254 } 2255 2256 func (n *NotifyRouter) HandleTeamDeleted(ctx context.Context, teamID keybase1.TeamID) { 2257 if n == nil { 2258 return 2259 } 2260 2261 var wg sync.WaitGroup 2262 n.G().Log.CDebugf(ctx, "+ Sending TeamDeleted notification") 2263 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2264 if n.getNotificationChannels(id).Team { 2265 wg.Add(1) 2266 go func() { 2267 _ = (keybase1.NotifyTeamClient{ 2268 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2269 }).TeamDeleted(context.Background(), teamID) 2270 wg.Done() 2271 }() 2272 } 2273 return true 2274 }) 2275 wg.Wait() 2276 2277 n.runListeners(func(listener NotifyListener) { 2278 listener.TeamDeleted(teamID) 2279 }) 2280 n.G().Log.CDebugf(ctx, "- Sent TeamDeleted notification") 2281 } 2282 2283 func (n *NotifyRouter) HandleTeamExit(ctx context.Context, teamID keybase1.TeamID) { 2284 if n == nil { 2285 return 2286 } 2287 2288 var wg sync.WaitGroup 2289 n.G().Log.CDebugf(ctx, "+ Sending TeamExit notification") 2290 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2291 if n.getNotificationChannels(id).Team { 2292 wg.Add(1) 2293 go func() { 2294 _ = (keybase1.NotifyTeamClient{ 2295 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2296 }).TeamExit(context.Background(), teamID) 2297 wg.Done() 2298 }() 2299 } 2300 return true 2301 }) 2302 wg.Wait() 2303 2304 n.runListeners(func(listener NotifyListener) { 2305 listener.TeamExit(teamID) 2306 }) 2307 n.G().Log.CDebugf(ctx, "- Sent TeamExit notification") 2308 } 2309 2310 func (n *NotifyRouter) HandleTeamRoleMapChanged(ctx context.Context, version keybase1.UserTeamVersion) { 2311 if n == nil { 2312 return 2313 } 2314 2315 var wg sync.WaitGroup 2316 n.G().Log.CDebugf(ctx, "+ Sending TeamRoleMapChanged notification") 2317 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2318 if n.getNotificationChannels(id).Team { 2319 wg.Add(1) 2320 go func() { 2321 _ = (keybase1.NotifyTeamClient{ 2322 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2323 }).TeamRoleMapChanged(context.Background(), version) 2324 wg.Done() 2325 }() 2326 } 2327 return true 2328 }) 2329 wg.Wait() 2330 2331 n.runListeners(func(listener NotifyListener) { 2332 listener.TeamRoleMapChanged(version) 2333 }) 2334 n.G().Log.CDebugf(ctx, "- Sent TeamRoleMapChanged notification (version %d)", version) 2335 } 2336 2337 func (n *NotifyRouter) HandleUserBlocked(ctx context.Context, b keybase1.UserBlockedBody) { 2338 if n == nil { 2339 return 2340 } 2341 2342 summary := b.Summarize() 2343 2344 var wg sync.WaitGroup 2345 n.G().Log.CDebugf(ctx, "+ Sending UserBlocked notification: %+v", b) 2346 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2347 if n.getNotificationChannels(id).Tracking { 2348 wg.Add(1) 2349 go func() { 2350 _ = (keybase1.NotifyTrackingClient{ 2351 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2352 }).NotifyUserBlocked(context.Background(), summary) 2353 wg.Done() 2354 }() 2355 } 2356 return true 2357 }) 2358 wg.Wait() 2359 2360 n.runListeners(func(listener NotifyListener) { 2361 listener.UserBlocked(b) 2362 }) 2363 n.G().Log.CDebugf(ctx, "- Sent UserBlocked notification") 2364 } 2365 2366 func (n *NotifyRouter) HandleTeamAbandoned(ctx context.Context, teamID keybase1.TeamID) { 2367 if n == nil { 2368 return 2369 } 2370 2371 var wg sync.WaitGroup 2372 n.G().Log.CDebugf(ctx, "+ Sending TeamAbandoned notification") 2373 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2374 if n.getNotificationChannels(id).Team { 2375 wg.Add(1) 2376 go func() { 2377 _ = (keybase1.NotifyTeamClient{ 2378 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2379 }).TeamAbandoned(context.Background(), teamID) 2380 wg.Done() 2381 }() 2382 } 2383 return true 2384 }) 2385 wg.Wait() 2386 2387 n.runListeners(func(listener NotifyListener) { 2388 listener.TeamExit(teamID) 2389 }) 2390 n.G().Log.CDebugf(ctx, "- Sent TeamAbandoned notification") 2391 } 2392 2393 func (n *NotifyRouter) HandleNewlyAddedToTeam(ctx context.Context, teamID keybase1.TeamID) { 2394 if n == nil { 2395 return 2396 } 2397 2398 var wg sync.WaitGroup 2399 n.G().Log.CDebugf(ctx, "+ Sending NewlyAddedToTeam notification") 2400 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2401 if n.getNotificationChannels(id).Team { 2402 wg.Add(1) 2403 go func() { 2404 _ = (keybase1.NotifyTeamClient{ 2405 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2406 }).NewlyAddedToTeam(context.Background(), teamID) 2407 wg.Done() 2408 }() 2409 } 2410 return true 2411 }) 2412 wg.Wait() 2413 2414 n.runListeners(func(listener NotifyListener) { 2415 listener.NewlyAddedToTeam(teamID) 2416 }) 2417 n.G().Log.CDebugf(ctx, "- Sent NewlyAddedToTeam notification") 2418 } 2419 2420 func (n *NotifyRouter) HandleNewTeamEK(ctx context.Context, teamID keybase1.TeamID, 2421 generation keybase1.EkGeneration) { 2422 if n == nil { 2423 return 2424 } 2425 2426 arg := keybase1.NewTeamEkArg{ 2427 Id: teamID, 2428 Generation: generation, 2429 } 2430 2431 var wg sync.WaitGroup 2432 n.G().Log.CDebugf(ctx, "+ Sending NewTeamEK notification") 2433 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2434 if n.getNotificationChannels(id).Ephemeral { 2435 wg.Add(1) 2436 go func() { 2437 _ = (keybase1.NotifyEphemeralClient{ 2438 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2439 }).NewTeamEk(context.Background(), arg) 2440 wg.Done() 2441 }() 2442 } 2443 return true 2444 }) 2445 wg.Wait() 2446 2447 n.runListeners(func(listener NotifyListener) { 2448 listener.NewTeamEK(teamID, generation) 2449 }) 2450 n.G().Log.CDebugf(ctx, "- Sent NewTeamEK notification") 2451 } 2452 2453 func (n *NotifyRouter) HandleNewTeambotEK(ctx context.Context, teamID keybase1.TeamID, 2454 generation keybase1.EkGeneration) { 2455 if n == nil { 2456 return 2457 } 2458 2459 arg := keybase1.NewTeambotEkArg{ 2460 Id: teamID, 2461 Generation: generation, 2462 } 2463 2464 var wg sync.WaitGroup 2465 n.G().Log.CDebugf(ctx, "+ Sending NewTeambotEK notification") 2466 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2467 if n.getNotificationChannels(id).Ephemeral { 2468 wg.Add(1) 2469 go func() { 2470 _ = (keybase1.NotifyEphemeralClient{ 2471 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2472 }).NewTeambotEk(context.Background(), arg) 2473 wg.Done() 2474 }() 2475 } 2476 return true 2477 }) 2478 wg.Wait() 2479 2480 n.runListeners(func(listener NotifyListener) { 2481 listener.NewTeambotEK(teamID, generation) 2482 }) 2483 n.G().Log.CDebugf(ctx, "- Sent NewTeambotEK notification") 2484 } 2485 2486 func (n *NotifyRouter) HandleTeambotEKNeeded(ctx context.Context, teamID keybase1.TeamID, 2487 botUID keybase1.UID, generation keybase1.EkGeneration, forceCreateGen *keybase1.EkGeneration) { 2488 if n == nil { 2489 return 2490 } 2491 2492 arg := keybase1.TeambotEkNeededArg{ 2493 Id: teamID, 2494 Uid: botUID, 2495 Generation: generation, 2496 ForceCreateGeneration: forceCreateGen, 2497 } 2498 2499 var wg sync.WaitGroup 2500 n.G().Log.CDebugf(ctx, "+ Sending TeambotEKNeeded notification") 2501 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2502 if n.getNotificationChannels(id).Ephemeral { 2503 wg.Add(1) 2504 go func() { 2505 _ = (keybase1.NotifyEphemeralClient{ 2506 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2507 }).TeambotEkNeeded(context.Background(), arg) 2508 wg.Done() 2509 }() 2510 } 2511 return true 2512 }) 2513 wg.Wait() 2514 2515 n.runListeners(func(listener NotifyListener) { 2516 listener.TeambotEKNeeded(teamID, botUID, generation, forceCreateGen) 2517 }) 2518 n.G().Log.CDebugf(ctx, "- Sent TeambotEKNeeded notification") 2519 } 2520 2521 func (n *NotifyRouter) HandleNewTeambotKey(ctx context.Context, teamID keybase1.TeamID, 2522 app keybase1.TeamApplication, generation keybase1.TeambotKeyGeneration) { 2523 if n == nil { 2524 return 2525 } 2526 2527 arg := keybase1.NewTeambotKeyArg{ 2528 Id: teamID, 2529 Application: app, 2530 Generation: generation, 2531 } 2532 2533 var wg sync.WaitGroup 2534 n.G().Log.CDebugf(ctx, "+ Sending NewTeambotKey notification") 2535 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2536 if n.getNotificationChannels(id).Teambot { 2537 wg.Add(1) 2538 go func() { 2539 _ = (keybase1.NotifyTeambotClient{ 2540 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2541 }).NewTeambotKey(context.Background(), arg) 2542 wg.Done() 2543 }() 2544 } 2545 return true 2546 }) 2547 wg.Wait() 2548 2549 n.runListeners(func(listener NotifyListener) { 2550 listener.NewTeambotKey(teamID, generation) 2551 }) 2552 n.G().Log.CDebugf(ctx, "- Sent NewTeambotKey notification") 2553 } 2554 2555 func (n *NotifyRouter) HandleTeambotKeyNeeded(ctx context.Context, teamID keybase1.TeamID, 2556 botUID keybase1.UID, app keybase1.TeamApplication, generation keybase1.TeambotKeyGeneration) { 2557 if n == nil { 2558 return 2559 } 2560 2561 arg := keybase1.TeambotKeyNeededArg{ 2562 Id: teamID, 2563 Application: app, 2564 Uid: botUID, 2565 Generation: generation, 2566 } 2567 2568 var wg sync.WaitGroup 2569 n.G().Log.CDebugf(ctx, "+ Sending TeambotKeyNeeded notification") 2570 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2571 if n.getNotificationChannels(id).Teambot { 2572 wg.Add(1) 2573 go func() { 2574 _ = (keybase1.NotifyTeambotClient{ 2575 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2576 }).TeambotKeyNeeded(context.Background(), arg) 2577 wg.Done() 2578 }() 2579 } 2580 return true 2581 }) 2582 wg.Wait() 2583 2584 n.runListeners(func(listener NotifyListener) { 2585 listener.TeambotKeyNeeded(teamID, botUID, generation) 2586 }) 2587 n.G().Log.CDebugf(ctx, "- Sent TeambotKeyNeeded notification") 2588 } 2589 2590 func (n *NotifyRouter) HandleAvatarUpdated(ctx context.Context, name string, formats []keybase1.AvatarFormat, 2591 typ keybase1.AvatarUpdateType) { 2592 if n == nil { 2593 return 2594 } 2595 arg := keybase1.AvatarUpdatedArg{ 2596 Name: name, 2597 Formats: formats, 2598 Typ: typ, 2599 } 2600 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2601 if n.getNotificationChannels(id).Team { 2602 go func() { 2603 _ = (keybase1.NotifyTeamClient{ 2604 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2605 }).AvatarUpdated(context.Background(), arg) 2606 }() 2607 } 2608 return true 2609 }) 2610 2611 n.runListeners(func(listener NotifyListener) { 2612 listener.AvatarUpdated(name, formats) 2613 }) 2614 } 2615 2616 func (n *NotifyRouter) HandlePhoneNumbersChanged(ctx context.Context, list []keybase1.UserPhoneNumber, category string, phoneNumber keybase1.PhoneNumber) { 2617 if n == nil { 2618 return 2619 } 2620 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2621 if n.getNotificationChannels(id).Team { 2622 go func() { 2623 _ = (keybase1.NotifyPhoneNumberClient{ 2624 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2625 }).PhoneNumbersChanged(context.Background(), keybase1.PhoneNumbersChangedArg{ 2626 List: list, 2627 Category: category, 2628 PhoneNumber: phoneNumber, 2629 }) 2630 }() 2631 } 2632 return true 2633 }) 2634 2635 n.runListeners(func(listener NotifyListener) { 2636 listener.PhoneNumbersChanged(list, category, phoneNumber) 2637 }) 2638 } 2639 2640 func (n *NotifyRouter) HandleEmailAddressVerified(ctx context.Context, emailAddress keybase1.EmailAddress) { 2641 if n == nil { 2642 return 2643 } 2644 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2645 if n.getNotificationChannels(id).Team { 2646 go func() { 2647 _ = (keybase1.NotifyEmailAddressClient{ 2648 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2649 }).EmailAddressVerified(context.Background(), emailAddress) 2650 }() 2651 } 2652 return true 2653 }) 2654 2655 n.runListeners(func(listener NotifyListener) { 2656 listener.EmailAddressVerified(emailAddress) 2657 }) 2658 } 2659 2660 func (n *NotifyRouter) HandleEmailAddressChanged(ctx context.Context, list []keybase1.Email, category string, emailAddress keybase1.EmailAddress) { 2661 if n == nil { 2662 return 2663 } 2664 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2665 if n.getNotificationChannels(id).Team { 2666 go func() { 2667 _ = (keybase1.NotifyEmailAddressClient{ 2668 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2669 }).EmailsChanged(context.Background(), keybase1.EmailsChangedArg{ 2670 List: list, 2671 Category: category, 2672 Email: emailAddress, 2673 }) 2674 }() 2675 } 2676 return true 2677 }) 2678 2679 n.runListeners(func(listener NotifyListener) { 2680 listener.EmailsChanged(list, category, emailAddress) 2681 }) 2682 } 2683 2684 func (n *NotifyRouter) HandleChatPaymentInfo(ctx context.Context, uid keybase1.UID, convID chat1.ConversationID, msgID chat1.MessageID, info chat1.UIPaymentInfo) { 2685 if n == nil { 2686 return 2687 } 2688 var wg sync.WaitGroup 2689 n.G().Log.CDebugf(ctx, "+ Sending ChatPaymentInfo notification") 2690 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2691 if n.shouldSendChatNotification(id, chat1.TopicType_NONE) { 2692 wg.Add(1) 2693 go func() { 2694 _ = (chat1.NotifyChatClient{ 2695 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2696 }).ChatPaymentInfo(context.Background(), chat1.ChatPaymentInfoArg{ 2697 Uid: uid, 2698 ConvID: convID, 2699 MsgID: msgID, 2700 Info: info, 2701 }) 2702 wg.Done() 2703 }() 2704 } 2705 return true 2706 }) 2707 wg.Wait() 2708 2709 n.runListeners(func(listener NotifyListener) { 2710 listener.ChatPaymentInfo(uid, convID, msgID, info) 2711 }) 2712 n.G().Log.CDebugf(ctx, "- Sent ChatPaymentInfo notification") 2713 } 2714 2715 func (n *NotifyRouter) HandleChatRequestInfo(ctx context.Context, uid keybase1.UID, convID chat1.ConversationID, msgID chat1.MessageID, info chat1.UIRequestInfo) { 2716 if n == nil { 2717 return 2718 } 2719 var wg sync.WaitGroup 2720 n.G().Log.CDebugf(ctx, "+ Sending ChatRequestInfo notification") 2721 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2722 if n.shouldSendChatNotification(id, chat1.TopicType_NONE) { 2723 wg.Add(1) 2724 go func() { 2725 _ = (chat1.NotifyChatClient{ 2726 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2727 }).ChatRequestInfo(context.Background(), chat1.ChatRequestInfoArg{ 2728 Uid: uid, 2729 ConvID: convID, 2730 MsgID: msgID, 2731 Info: info, 2732 }) 2733 wg.Done() 2734 }() 2735 } 2736 return true 2737 }) 2738 wg.Wait() 2739 2740 n.runListeners(func(listener NotifyListener) { 2741 listener.ChatRequestInfo(uid, convID, msgID, info) 2742 }) 2743 n.G().Log.CDebugf(ctx, "- Sent ChatRequestInfo notification") 2744 } 2745 2746 func (n *NotifyRouter) HandlePasswordChanged(ctx context.Context, passphraseState keybase1.PassphraseState) { 2747 if n == nil { 2748 return 2749 } 2750 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2751 if n.getNotificationChannels(id).Users { 2752 go func() { 2753 _ = (keybase1.NotifyUsersClient{ 2754 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2755 }).PasswordChanged(context.Background(), passphraseState) 2756 }() 2757 } 2758 return true 2759 }) 2760 2761 n.runListeners(func(listener NotifyListener) { 2762 listener.PasswordChanged() 2763 }) 2764 } 2765 2766 // RootAuditError is called when the merkle root auditor finds an invalid skip 2767 // sequence in a random old block. 2768 func (n *NotifyRouter) HandleRootAuditError(msg string) { 2769 if n == nil { 2770 return 2771 } 2772 n.G().Log.Debug("+ Sending merkle tree audit notification") 2773 // For all connections we currently have open... 2774 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2775 // If the connection wants the `Session` notification type 2776 if n.getNotificationChannels(id).Audit { 2777 // In the background do... 2778 go func() { 2779 // A send of a `RootAuditError` RPC 2780 _ = (keybase1.NotifyAuditClient{ 2781 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2782 }).RootAuditError(context.Background(), msg) 2783 }() 2784 } 2785 return true 2786 }) 2787 2788 n.runListeners(func(listener NotifyListener) { 2789 listener.RootAuditError(msg) 2790 }) 2791 2792 n.G().Log.Debug("- merkle tree audit notification sent") 2793 } 2794 2795 func (n *NotifyRouter) HandleBoxAuditError(ctx context.Context, msg string) { 2796 if n == nil { 2797 return 2798 } 2799 n.G().Log.CDebugf(ctx, "+ Sending BoxAuditError notification") 2800 defer n.G().Log.CDebugf(ctx, "- Sending BoxAuditError notification") 2801 2802 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2803 if n.getNotificationChannels(id).Audit { 2804 go func() { 2805 _ = (keybase1.NotifyAuditClient{ 2806 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2807 }).BoxAuditError(context.Background(), msg) 2808 }() 2809 } 2810 return true 2811 }) 2812 2813 n.runListeners(func(listener NotifyListener) { 2814 listener.BoxAuditError(msg) 2815 }) 2816 } 2817 2818 func (n *NotifyRouter) HandleRuntimeStatsUpdate(ctx context.Context, stats *keybase1.RuntimeStats) { 2819 if n == nil { 2820 return 2821 } 2822 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2823 if n.getNotificationChannels(id).Runtimestats { 2824 go func() { 2825 _ = (keybase1.NotifyRuntimeStatsClient{ 2826 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2827 }).RuntimeStatsUpdate(ctx, stats) 2828 }() 2829 } 2830 return true 2831 }) 2832 n.runListeners(func(listener NotifyListener) { 2833 listener.RuntimeStatsUpdate(stats) 2834 }) 2835 } 2836 2837 func (n *NotifyRouter) HandleHTTPSrvInfoUpdate(ctx context.Context, info keybase1.HttpSrvInfo) { 2838 if n == nil { 2839 return 2840 } 2841 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2842 if n.getNotificationChannels(id).Service { 2843 go func() { 2844 _ = (keybase1.NotifyServiceClient{ 2845 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2846 }).HTTPSrvInfoUpdate(ctx, info) 2847 }() 2848 } 2849 return true 2850 }) 2851 n.runListeners(func(listener NotifyListener) { 2852 listener.HTTPSrvInfoUpdate(info) 2853 }) 2854 } 2855 2856 func (n *NotifyRouter) HandleHandleKeybaseLink(ctx context.Context, link string, deferred bool) { 2857 if n == nil { 2858 return 2859 } 2860 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2861 if n.getNotificationChannels(id).Service { 2862 go func() { 2863 _ = (keybase1.NotifyServiceClient{ 2864 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2865 }).HandleKeybaseLink(ctx, keybase1.HandleKeybaseLinkArg{ 2866 Link: link, 2867 Deferred: deferred, 2868 }) 2869 }() 2870 } 2871 return true 2872 }) 2873 n.runListeners(func(listener NotifyListener) { 2874 listener.HandleKeybaseLink(link, deferred) 2875 }) 2876 } 2877 2878 func (n *NotifyRouter) HandleIdentifyUpdate(ctx context.Context, okUsernames []string, brokenUsernames []string) { 2879 if n == nil { 2880 return 2881 } 2882 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2883 if n.getNotificationChannels(id).Users { 2884 go func() { 2885 _ = (keybase1.NotifyUsersClient{ 2886 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2887 }).IdentifyUpdate(ctx, keybase1.IdentifyUpdateArg{ 2888 OkUsernames: okUsernames, 2889 BrokenUsernames: brokenUsernames, 2890 }) 2891 }() 2892 } 2893 return true 2894 }) 2895 n.runListeners(func(listener NotifyListener) { 2896 listener.IdentifyUpdate(okUsernames, brokenUsernames) 2897 }) 2898 } 2899 2900 func (n *NotifyRouter) HandleFeaturedBots(ctx context.Context, bots []keybase1.FeaturedBot, limit, offset int) { 2901 if n == nil { 2902 return 2903 } 2904 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2905 if n.getNotificationChannels(id).FeaturedBots { 2906 go func() { 2907 _ = (keybase1.NotifyFeaturedBotsClient{ 2908 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2909 }).FeaturedBotsUpdate(ctx, keybase1.FeaturedBotsUpdateArg{ 2910 Bots: bots, 2911 Limit: limit, 2912 Offset: offset, 2913 }) 2914 }() 2915 } 2916 return true 2917 }) 2918 n.runListeners(func(listener NotifyListener) { 2919 listener.FeaturedBotsUpdate(bots, limit, offset) 2920 }) 2921 } 2922 2923 func (n *NotifyRouter) HandleSaltpackOperationStart(ctx context.Context, opType keybase1.SaltpackOperationType, filename string) { 2924 if n == nil { 2925 return 2926 } 2927 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2928 if n.getNotificationChannels(id).Saltpack { 2929 // note there's no goroutine here on purpose 2930 // (notification ordering) 2931 _ = (keybase1.NotifySaltpackClient{ 2932 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2933 }).SaltpackOperationStart(context.Background(), keybase1.SaltpackOperationStartArg{ 2934 OpType: opType, 2935 Filename: filename, 2936 }) 2937 } 2938 return true 2939 }) 2940 2941 n.runListeners(func(listener NotifyListener) { 2942 listener.SaltpackOperationStart(opType, filename) 2943 }) 2944 } 2945 2946 func (n *NotifyRouter) HandleSaltpackOperationProgress(ctx context.Context, opType keybase1.SaltpackOperationType, filename string, bytesComplete, bytesTotal int64) { 2947 if n == nil { 2948 return 2949 } 2950 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2951 if n.getNotificationChannels(id).Saltpack { 2952 // note there's no goroutine here on purpose 2953 // (notification ordering) 2954 _ = (keybase1.NotifySaltpackClient{ 2955 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2956 }).SaltpackOperationProgress(context.Background(), keybase1.SaltpackOperationProgressArg{ 2957 OpType: opType, 2958 Filename: filename, 2959 BytesComplete: bytesComplete, 2960 BytesTotal: bytesTotal, 2961 }) 2962 } 2963 return true 2964 }) 2965 2966 n.runListeners(func(listener NotifyListener) { 2967 listener.SaltpackOperationDone(opType, filename) 2968 }) 2969 } 2970 2971 func (n *NotifyRouter) HandleSaltpackOperationDone(ctx context.Context, opType keybase1.SaltpackOperationType, filename string) { 2972 if n == nil { 2973 return 2974 } 2975 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2976 if n.getNotificationChannels(id).Saltpack { 2977 // note there's no goroutine here on purpose 2978 // (notification ordering) 2979 _ = (keybase1.NotifySaltpackClient{ 2980 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 2981 }).SaltpackOperationDone(context.Background(), keybase1.SaltpackOperationDoneArg{ 2982 OpType: opType, 2983 Filename: filename, 2984 }) 2985 } 2986 return true 2987 }) 2988 2989 n.runListeners(func(listener NotifyListener) { 2990 listener.SaltpackOperationDone(opType, filename) 2991 }) 2992 } 2993 2994 func (n *NotifyRouter) HandleUpdateInviteCounts(ctx context.Context, counts keybase1.InviteCounts) { 2995 if n == nil { 2996 return 2997 } 2998 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 2999 if n.getNotificationChannels(id).App { 3000 go func() { 3001 _ = (keybase1.NotifyInviteFriendsClient{ 3002 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 3003 }).UpdateInviteCounts(context.Background(), counts) 3004 }() 3005 } 3006 return true 3007 }) 3008 3009 n.runListeners(func(listener NotifyListener) { 3010 listener.UpdateInviteCounts(counts) 3011 }) 3012 } 3013 3014 func (n *NotifyRouter) HandleTeamTreeMembershipsPartial(ctx context.Context, 3015 result keybase1.TeamTreeMembership) { 3016 3017 if n == nil { 3018 return 3019 } 3020 3021 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 3022 if n.getNotificationChannels(id).Team { 3023 go func() { 3024 _ = (keybase1.NotifyTeamClient{ 3025 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 3026 }).TeamTreeMembershipsPartial(context.Background(), result) 3027 }() 3028 } 3029 return true 3030 }) 3031 3032 n.runListeners(func(listener NotifyListener) { 3033 listener.TeamTreeMembershipsPartial(result) 3034 }) 3035 } 3036 3037 func (n *NotifyRouter) HandleTeamTreeMembershipsDone(ctx context.Context, result keybase1.TeamTreeMembershipsDoneResult) { 3038 if n == nil { 3039 return 3040 } 3041 3042 n.cm.ApplyAll(func(id ConnectionID, xp rpc.Transporter) bool { 3043 if n.getNotificationChannels(id).Team { 3044 go func() { 3045 _ = (keybase1.NotifyTeamClient{ 3046 Cli: rpc.NewClient(xp, NewContextifiedErrorUnwrapper(n.G()), nil), 3047 }).TeamTreeMembershipsDone(context.Background(), result) 3048 }() 3049 } 3050 return true 3051 }) 3052 3053 n.runListeners(func(listener NotifyListener) { 3054 listener.TeamTreeMembershipsDone(result) 3055 }) 3056 }