11package proxy
22
33import (
4+ "context"
45 "crypto/ecdsa"
56 "fmt"
67 "sync"
@@ -24,7 +25,9 @@ type ClientManager struct {
2425
2526 cachedCli struct {
2627 sync.RWMutex
27- cli * upClient
28+ cli * upClient
29+ completionCtx context.Context
30+ completionDone context.CancelFunc
2831 }
2932}
3033
@@ -74,13 +77,49 @@ func (cliMgr *ClientManager) Client(ctx *gin.Context) *upClient {
7477 return cliMgr .cachedCli .cli
7578 }
7679 cliMgr .cachedCli .RUnlock ()
80+
7781 cliMgr .cachedCli .Lock ()
78- defer cliMgr .cachedCli .Unlock ()
7982 if cliMgr .cachedCli .cli != nil {
83+ defer cliMgr .cachedCli .Unlock ()
8084 return cliMgr .cachedCli .cli
8185 }
8286
83- return nil
87+ var completionCtx context.Context
88+ // Check if completion context is set
89+ if cliMgr .cachedCli .completionCtx != nil {
90+ completionCtx = cliMgr .cachedCli .completionCtx
91+ } else {
92+ // Set new completion context and launch login goroutine
93+ ctx , completionDone := context .WithCancel (context .TODO ())
94+ cliMgr .cachedCli .completionCtx = ctx
95+
96+ // Launch login goroutine
97+ go func () {
98+ defer completionDone ()
99+
100+ loginCli := cliMgr .doLogin ()
101+ if loginResult , err := loginCli .Login (context .Background ()); err == nil {
102+ loginCli .loginToken = loginResult .Token
103+
104+ cliMgr .cachedCli .Lock ()
105+ cliMgr .cachedCli .cli = loginCli
106+ cliMgr .cachedCli .completionCtx = nil
107+ cliMgr .cachedCli .Unlock ()
108+ }
109+ }()
110+ }
111+ cliMgr .cachedCli .Unlock ()
112+
113+ // Wait for completion or request cancellation
114+ select {
115+ case <- ctx .Done ():
116+ return nil
117+ case <- completionCtx .Done ():
118+ cliMgr .cachedCli .Lock ()
119+ cli := cliMgr .cachedCli .cli
120+ cliMgr .cachedCli .Unlock ()
121+ return cli
122+ }
84123}
85124
86125func (cliMgr * ClientManager ) OnError (isUnauth bool ) {
0 commit comments