package release import ( "context" "os" "sync/atomic" "time" "github.com/carlosframework/platform/internal/rootstate" ) type ReleaseExclusion struct { Open func() (rootstate.Store, error) Wait time.Duration } type releaseHeldKey struct{} type releaseHeld struct { owner *ReleaseExclusion active atomic.Bool } func (x *ReleaseExclusion) Check(ctx context.Context) error { held, _ := ctx.Value(releaseHeldKey{}).(*releaseHeld) if x == nil || held == nil || held.owner != x || !held.active.Load() { return os.ErrPermission } return ctx.Err() } func (x *ReleaseExclusion) With(ctx context.Context, fn func(context.Context) error) error { if x == nil || x.Open == nil || fn == nil { return os.ErrPermission } if ctx.Value(releaseHeldKey{}) != nil { if err := x.Check(ctx); err != nil { return err } return fn(ctx) } store, err := x.Open() if err != nil { return err } if store == nil { return os.ErrPermission } defer store.Close() wait := ctx cancel := func() {} if x.Wait > 0 { wait, cancel = context.WithTimeout(ctx, x.Wait) } defer cancel() return rootstate.WithRelease(wait, store, func() error { cancel() held := &releaseHeld{owner: x} held.active.Store(true) defer held.active.Store(false) return fn(context.WithValue(ctx, releaseHeldKey{}, held)) }) }