@@ -26,17 +26,28 @@ func NewScopeWaiter() *ScopeWaiter {
2626 return & ScopeWaiter {pending : make (map [string ]* pendingAuth )}
2727}
2828
29- // Wait blocks until Signal is called for the given state or the timeout expires.
30- // The scopes and account are stored so the callback can retrieve them via Lookup.
31- func (w * ScopeWaiter ) Wait (state string , timeout time.Duration , scopes []string , account string ) error {
29+ // Register adds a pending auth entry so that Signal can resolve it
30+ // even before Await is called — eliminating the race where Signal
31+ // fires between NotifyLink and Await.
32+ func (w * ScopeWaiter ) Register (state string , scopes []string , account string ) {
3233 w .mu .Lock ()
33- p : = & pendingAuth {
34+ w . pending [ state ] = & pendingAuth {
3435 ch : make (chan error , 1 ),
3536 scopes : scopes ,
3637 account : account ,
3738 }
38- w .pending [state ] = p
3939 w .mu .Unlock ()
40+ }
41+
42+ // Await blocks until Signal is called for a previously registered state
43+ // or the timeout expires.
44+ func (w * ScopeWaiter ) Await (state string , timeout time.Duration ) error {
45+ w .mu .Lock ()
46+ p , ok := w .pending [state ]
47+ w .mu .Unlock ()
48+ if ! ok {
49+ return errors .New ("state not registered" )
50+ }
4051
4152 defer func () {
4253 w .mu .Lock ()
@@ -52,6 +63,13 @@ func (w *ScopeWaiter) Wait(state string, timeout time.Duration, scopes []string,
5263 }
5364}
5465
66+ // Wait registers a state and blocks until Signal is called or timeout.
67+ // For race-free usage prefer Register + Await.
68+ func (w * ScopeWaiter ) Wait (state string , timeout time.Duration , scopes []string , account string ) error {
69+ w .Register (state , scopes , account )
70+ return w .Await (state , timeout )
71+ }
72+
5573// Lookup returns the scopes and account associated with a pending state.
5674// Returns false if no pending auth exists for that state.
5775func (w * ScopeWaiter ) Lookup (state string ) (scopes []string , account string , ok bool ) {
0 commit comments