package util
import (
"context"
"sync"
"time"
"go.uber.org/atomic"
)
type WaitTrigger struct {
completed atomic.Bool
mut *sync.Mutex
cond *sync.Cond
}
func NewWaitTrigger() *WaitTrigger {
var mut sync.Mutex
cond := sync.NewCond(&mut)
return &WaitTrigger{mut: &mut, cond: cond}
}
func (wt *WaitTrigger) Trigger() {
wt.mut.Lock()
defer wt.mut.Unlock()
wt.completed.Store(true)
wt.cond.Broadcast()
}
func (wt *WaitTrigger) Wait(timeout time.Duration) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return wt.WaitContext(ctx)
}
func (wt *WaitTrigger) WaitContext(ctx context.Context) error {
parentCtx := ctx
ctx, cancel := context.WithCancel(parentCtx)
defer cancel()
go func() {
<-ctx.Done()
if parentCtx.Err() != nil {
wt.cond.Broadcast()
}
}()
wt.mut.Lock()
for ctx.Err() == nil && !wt.completed.Load() {
wt.cond.Wait()
}
err := parentCtx.Err()
wt.mut.Unlock()
return err
}