github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/badges/badger.go (about)

     1  // Copyright 2016 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package badges
     5  
     6  import (
     7  	"golang.org/x/net/context"
     8  
     9  	"github.com/keybase/client/go/gregor"
    10  	"github.com/keybase/client/go/libkb"
    11  	"github.com/keybase/client/go/protocol/chat1"
    12  	"github.com/keybase/client/go/protocol/gregor1"
    13  	"github.com/keybase/client/go/protocol/keybase1"
    14  	"github.com/keybase/client/go/protocol/stellar1"
    15  )
    16  
    17  type InboxVersionSource interface {
    18  	GetInboxVersion(context.Context, gregor1.UID) (chat1.InboxVers, error)
    19  }
    20  
    21  type nullInboxVersionSource struct {
    22  }
    23  
    24  func (n nullInboxVersionSource) GetInboxVersion(ctx context.Context, uid gregor1.UID) (chat1.InboxVers, error) {
    25  	return chat1.InboxVers(0), nil
    26  }
    27  
    28  // Badger keeps a BadgeState up to date and broadcasts it to electron.
    29  // This is the client-specific glue.
    30  // The state is kept up to date by subscribing to:
    31  // - All gregor state updates
    32  // - All chat.activity gregor OOBMs
    33  // - Logout
    34  type Badger struct {
    35  	libkb.Contextified
    36  	badgeState     *BadgeState
    37  	iboxVersSource InboxVersionSource
    38  	notifyCh       chan keybase1.BadgeState
    39  	shutdownCh     chan struct{}
    40  }
    41  
    42  func NewBadger(g *libkb.GlobalContext) *Badger {
    43  	b := &Badger{
    44  		Contextified:   libkb.NewContextified(g),
    45  		badgeState:     NewBadgeState(g.Log, g.Env),
    46  		iboxVersSource: nullInboxVersionSource{},
    47  		notifyCh:       make(chan keybase1.BadgeState, 1000),
    48  		shutdownCh:     make(chan struct{}),
    49  	}
    50  	go b.notifyLoop()
    51  	g.PushShutdownHook(func(mctx libkb.MetaContext) error {
    52  		close(b.shutdownCh)
    53  		return nil
    54  	})
    55  	return b
    56  }
    57  
    58  func (b *Badger) notifyLoop() {
    59  	for {
    60  		select {
    61  		case state := <-b.notifyCh:
    62  			b.G().NotifyRouter.HandleBadgeState(state)
    63  		case <-b.shutdownCh:
    64  			return
    65  		}
    66  	}
    67  }
    68  
    69  func (b *Badger) SetLocalChatState(s LocalChatState) {
    70  	b.badgeState.SetLocalChatState(s)
    71  }
    72  
    73  func (b *Badger) SetInboxVersionSource(s InboxVersionSource) {
    74  	b.iboxVersSource = s
    75  }
    76  
    77  func (b *Badger) PushState(ctx context.Context, state gregor.State) {
    78  	b.G().Log.CDebugf(ctx, "Badger update with gregor state")
    79  	if err := b.badgeState.UpdateWithGregor(ctx, state); err != nil {
    80  		b.G().Log.Warning("Badger (PushState) UpdateWithGregor failed: %v", err)
    81  	}
    82  	if err := b.Send(ctx); err != nil {
    83  		b.G().Log.Warning("Badger send (PushState) failed: %v", err)
    84  	}
    85  }
    86  
    87  func (b *Badger) PushChatUpdate(ctx context.Context, update chat1.UnreadUpdate, inboxVers chat1.InboxVers) {
    88  	b.G().Log.CDebugf(ctx, "Badger update with chat update")
    89  	b.badgeState.UpdateWithChat(ctx, update, inboxVers, b.G().IsMobileAppType())
    90  	if err := b.Send(ctx); err != nil {
    91  		b.G().Log.CDebugf(ctx, "Badger send (PushChatUpdate) failed: %v", err)
    92  	}
    93  }
    94  
    95  func (b *Badger) PushChatFullUpdate(ctx context.Context, update chat1.UnreadUpdateFull) {
    96  	b.G().Log.CDebugf(ctx, "Badger update with chat full update")
    97  	b.badgeState.UpdateWithChatFull(ctx, update, b.G().IsMobileAppType())
    98  	if err := b.Send(ctx); err != nil {
    99  		b.G().Log.CDebugf(ctx, "Badger send (PushChatFullUpdate) failed: %v", err)
   100  	}
   101  }
   102  
   103  func (b *Badger) GetInboxVersionForTest(ctx context.Context) (chat1.InboxVers, error) {
   104  	uid := b.G().Env.GetUID()
   105  	return b.iboxVersSource.GetInboxVersion(ctx, uid.ToBytes())
   106  }
   107  
   108  func (b *Badger) SetWalletAccountUnreadCount(ctx context.Context, accountID stellar1.AccountID, unreadCount int) {
   109  	changed := b.badgeState.SetWalletAccountUnreadCount(accountID, unreadCount)
   110  	if !changed {
   111  		return
   112  	}
   113  	b.G().Log.CDebugf(ctx, "Badger sending for SetWalletAccountUnreadCount: %s/%d", accountID, unreadCount)
   114  	if err := b.Send(ctx); err != nil {
   115  		b.G().Log.CDebugf(ctx, "Badger send (SetWalletAccountUnreadCount) failed: %s", err)
   116  	}
   117  }
   118  
   119  func (b *Badger) Clear(ctx context.Context) {
   120  	b.badgeState.Clear()
   121  	if err := b.Send(ctx); err != nil {
   122  		b.G().Log.CDebugf(ctx, "Badger send (clear) failed: %v", err)
   123  	}
   124  }
   125  
   126  // Send the badgestate to electron
   127  func (b *Badger) Send(ctx context.Context) error {
   128  	state, err := b.badgeState.Export(ctx)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	b.log(ctx, state)
   133  	b.notifyCh <- state
   134  	return nil
   135  }
   136  
   137  func (b *Badger) State() *BadgeState {
   138  	return b.badgeState
   139  }
   140  
   141  // Log a copy of the badgestate with some zeros stripped off for brevity.
   142  func (b *Badger) log(ctx context.Context, state1 keybase1.BadgeState) {
   143  	state2 := state1
   144  	state2.Conversations = nil
   145  	for index, c1 := range state1.Conversations {
   146  		if c1.IsEmpty() {
   147  			continue
   148  		}
   149  		c2id := c1.ConvID
   150  		if len(c1.ConvID) >= chat1.DbShortFormLen {
   151  			// This is the db short form for logging brevity only.
   152  			// Don't let this leave this method.
   153  			c2id = chat1.ConversationID([]byte(c1.ConvID)).DbShortForm()
   154  		}
   155  
   156  		c2 := keybase1.BadgeConversationInfo{
   157  			ConvID:         c2id,
   158  			UnreadMessages: c1.UnreadMessages,
   159  			BadgeCount:     c1.BadgeCount,
   160  		}
   161  		state2.Conversations = append(state2.Conversations, c2)
   162  		if index >= 50 {
   163  			b.G().Log.CDebugf(ctx, "Badger send: cutting off debug, too many convs")
   164  			break
   165  		}
   166  	}
   167  	b.G().Log.CDebugf(ctx, "Badger send: %+v", state2)
   168  }