github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/service/ui_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 service
     5  
     6  import (
     7  	"fmt"
     8  	"sync"
     9  	"time"
    10  
    11  	identify3 "github.com/keybase/client/go/identify3"
    12  	libkb "github.com/keybase/client/go/libkb"
    13  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    14  	"github.com/keybase/go-framed-msgpack-rpc/rpc"
    15  	context "golang.org/x/net/context"
    16  )
    17  
    18  type UIRouter struct {
    19  	sync.Mutex
    20  	libkb.Contextified
    21  	cm  *libkb.ConnectionManager
    22  	uis map[libkb.UIKind]libkb.ConnectionID
    23  }
    24  
    25  func NewUIRouter(g *libkb.GlobalContext) *UIRouter {
    26  	return &UIRouter{
    27  		Contextified: libkb.NewContextified(g),
    28  		cm:           g.ConnectionManager,
    29  		uis:          make(map[libkb.UIKind]libkb.ConnectionID),
    30  	}
    31  }
    32  
    33  func (u *UIRouter) Shutdown() {}
    34  
    35  func (u *UIRouter) SetUI(c libkb.ConnectionID, k libkb.UIKind) {
    36  	u.Lock()
    37  	defer u.Unlock()
    38  	u.G().Log.Debug("UIRouter: connection %v registering UI %s [%p]", c, k, u)
    39  	u.uis[k] = c
    40  }
    41  
    42  func (u *UIRouter) getUI(k libkb.UIKind) (rpc.Transporter, libkb.ConnectionID) {
    43  	u.Lock()
    44  	defer u.Unlock()
    45  	var ret rpc.Transporter
    46  	cid, ok := u.uis[k]
    47  	if ok {
    48  		if ret = u.cm.LookupConnection(cid); ret == nil {
    49  			u.G().Log.Debug("UIRouter: connection %v inactive, deleting registered UI %s", cid, k)
    50  			delete(u.uis, k)
    51  		}
    52  	}
    53  	return ret, cid
    54  }
    55  
    56  func (u *UIRouter) DumpUIs() map[libkb.UIKind]libkb.ConnectionID {
    57  	u.Lock()
    58  	defer u.Unlock()
    59  
    60  	// Copy the map
    61  	res := map[libkb.UIKind]libkb.ConnectionID{}
    62  	for k, v := range u.uis {
    63  		res[k] = v
    64  	}
    65  	return res
    66  }
    67  
    68  func (u *UIRouter) GetIdentifyUI() (libkb.IdentifyUI, error) {
    69  	x, _ := u.getUI(libkb.IdentifyUIKind)
    70  	if x == nil {
    71  		return nil, nil
    72  	}
    73  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(u.G()), nil)
    74  	iuicli := keybase1.IdentifyUiClient{Cli: cli}
    75  	sessionID, err := iuicli.DelegateIdentifyUI(context.TODO())
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	ret := &RemoteIdentifyUI{
    80  		sessionID:    sessionID,
    81  		uicli:        iuicli,
    82  		logUI:        NewLogUI(sessionID, cli),
    83  		Contextified: libkb.NewContextified(u.G()),
    84  	}
    85  	return ret, nil
    86  }
    87  
    88  func (u *UIRouter) GetIdentify3UI(m libkb.MetaContext) (keybase1.Identify3UiInterface, error) {
    89  	x, _ := u.getUI(libkb.Identify3UIKind)
    90  	if x == nil {
    91  		return nil, nil
    92  	}
    93  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(m.G()), nil)
    94  	id3cli := keybase1.Identify3UiClient{Cli: cli}
    95  	return id3cli, nil
    96  }
    97  
    98  func (u *UIRouter) GetIdentify3UIAdapter(m libkb.MetaContext) (libkb.IdentifyUI, error) {
    99  	id3i, err := u.GetIdentify3UI(m)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	if id3i == nil {
   104  		return nil, nil
   105  	}
   106  	return identify3.NewUIAdapterMakeSessionForUpcall(m, id3i)
   107  }
   108  
   109  func (u *UIRouter) GetChatUI() (libkb.ChatUI, error) {
   110  	x, _ := u.getUI(libkb.ChatUIKind)
   111  	if x == nil {
   112  		return nil, nil
   113  	}
   114  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(u.G()), nil)
   115  	return NewRemoteChatUI(0, cli), nil
   116  }
   117  
   118  func (u *UIRouter) GetLogUI() (libkb.LogUI, error) {
   119  	x, _ := u.getUI(libkb.LogUIKind)
   120  	if x == nil {
   121  		return nil, nil
   122  	}
   123  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(u.G()), nil)
   124  	return NewLogUI(0, cli), nil
   125  }
   126  
   127  func (u *UIRouter) GetIdentifyUICtx(ctx context.Context) (int, libkb.IdentifyUI, error) {
   128  	x, _ := u.getUI(libkb.IdentifyUIKind)
   129  	if x == nil {
   130  		return 0, nil, nil
   131  	}
   132  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(u.G()), nil)
   133  	iuicli := keybase1.IdentifyUiClient{Cli: cli}
   134  	sessionID, err := iuicli.DelegateIdentifyUI(ctx)
   135  	if err != nil {
   136  		return 0, nil, err
   137  	}
   138  	ret := &RemoteIdentifyUI{
   139  		sessionID:    sessionID,
   140  		uicli:        iuicli,
   141  		logUI:        NewLogUI(sessionID, cli),
   142  		Contextified: libkb.NewContextified(u.G()),
   143  	}
   144  	return sessionID, ret, nil
   145  }
   146  
   147  func (u *UIRouter) GetSecretUI(sessionID int) (ui libkb.SecretUI, err error) {
   148  	defer u.G().Trace("UIRouter#GetSecretUI", &err)()
   149  	x, _ := u.getUI(libkb.SecretUIKind)
   150  	if x == nil {
   151  		u.G().Log.Debug("| getUI(libkb.SecretUIKind) returned nil")
   152  		return nil, nil
   153  	}
   154  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(u.G()), nil)
   155  	scli := keybase1.SecretUiClient{Cli: cli}
   156  
   157  	u.G().Log.Debug("| returning delegated SecretUI with sessionID = %d", sessionID)
   158  	ret := &SecretUI{
   159  		cli:          &scli,
   160  		sessionID:    sessionID,
   161  		Contextified: libkb.NewContextified(u.G()),
   162  	}
   163  	return ret, nil
   164  }
   165  
   166  // WaitForClientType returns true if a ui of the specified type is registered,
   167  // or waits until timeout for such ui to register and returns false if this does
   168  // not happen.
   169  func (u *UIRouter) WaitForUIType(uiKind libkb.UIKind, timeout time.Duration) bool {
   170  	if x, _ := u.getUI(uiKind); x != nil {
   171  		return true
   172  	}
   173  	ticker := time.NewTicker(time.Second)
   174  	deadline := time.After(timeout)
   175  	defer ticker.Stop()
   176  	for {
   177  		select {
   178  		case <-ticker.C:
   179  			if x, _ := u.getUI(uiKind); x != nil {
   180  				return true
   181  			}
   182  		case <-deadline:
   183  			return false
   184  		}
   185  	}
   186  }
   187  
   188  func (u *UIRouter) GetHomeUI() (keybase1.HomeUIInterface, error) {
   189  	var err error
   190  	defer u.G().Trace(fmt.Sprintf("UIRouter#GetHomeUI [%p]", u), &err)()
   191  
   192  	x, _ := u.getUI(libkb.HomeUIKind)
   193  	if x == nil {
   194  		u.G().Log.Debug("| getUI(libkb.HomeUIKind) returned nil")
   195  		return nil, nil
   196  	}
   197  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(u.G()), nil)
   198  	uicli := keybase1.HomeUIClient{Cli: cli}
   199  	return uicli, nil
   200  }
   201  
   202  func (u *UIRouter) GetRekeyUI() (keybase1.RekeyUIInterface, int, error) {
   203  	var err error
   204  	defer u.G().Trace("UIRouter#GetRekeyUI", &err)()
   205  
   206  	x, cid := u.getUI(libkb.RekeyUIKind)
   207  	if x == nil {
   208  		u.G().Log.Debug("| getUI(libkb.RekeyUIKind) returned nil")
   209  		return nil, 0, nil
   210  	}
   211  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(u.G()), nil)
   212  	uicli := keybase1.RekeyUIClient{Cli: cli}
   213  	sessionID, err := uicli.DelegateRekeyUI(context.TODO())
   214  	if err != nil {
   215  		return nil, 0, err
   216  	}
   217  	ret := &RekeyUI{
   218  		Contextified: libkb.NewContextified(u.G()),
   219  		sessionID:    sessionID,
   220  		cli:          &uicli,
   221  		connectionID: cid,
   222  	}
   223  	return ret, sessionID, nil
   224  }
   225  
   226  func (u *UIRouter) getOrReuseRekeyUI(prev *RekeyUI) (ret *RekeyUI, err error) {
   227  	defer u.G().Trace("UIRouter#GetOrReuseRekeyUI", &err)()
   228  	x, cid := u.getUI(libkb.RekeyUIKind)
   229  
   230  	if x == nil {
   231  		return nil, nil
   232  	}
   233  
   234  	if prev != nil && prev.connectionID == cid {
   235  		return prev, nil
   236  	}
   237  
   238  	cli := rpc.NewClient(x, libkb.NewContextifiedErrorUnwrapper(u.G()), nil)
   239  	uicli := keybase1.RekeyUIClient{Cli: cli}
   240  	var sessionID int
   241  	sessionID, err = uicli.DelegateRekeyUI(context.TODO())
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  	ret = &RekeyUI{
   246  		Contextified: libkb.NewContextified(u.G()),
   247  		sessionID:    sessionID,
   248  		cli:          &uicli,
   249  		connectionID: cid,
   250  	}
   251  
   252  	return ret, nil
   253  }
   254  
   255  func (u *UIRouter) GetRekeyUINoSessionID() (ret keybase1.RekeyUIInterface, err error) {
   256  	defer u.G().Trace("UIRouter#GetRekeyUINoSessionID", &err)()
   257  	return u.getOrReuseRekeyUI(nil)
   258  }