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 }