pomerium/pkg/contextutil/contextutil.go
Caleb Doxsey 7eb7861f2c
core: fix graceful stop (#4865)
* core/grpc: fix graceful stop

* core/http: add graceful stop serve
2023-12-29 10:18:08 -07:00

88 lines
1.7 KiB
Go

// Package contextutil contains functions for working with contexts.
package contextutil
import (
"context"
"time"
)
type mergedCtx struct {
ctx1, ctx2 context.Context
doneCtx context.Context
doneCancel context.CancelFunc
}
// Merge merges two contexts into a single context.
func Merge(ctx1, ctx2 context.Context) (context.Context, context.CancelFunc) {
mc := &mergedCtx{
ctx1: ctx1,
ctx2: ctx2,
}
mc.doneCtx, mc.doneCancel = context.WithCancel(context.Background())
go func() {
select {
case <-ctx1.Done():
case <-ctx2.Done():
case <-mc.doneCtx.Done():
}
mc.doneCancel()
}()
return mc, mc.doneCancel
}
func (mc *mergedCtx) Deadline() (deadline time.Time, ok bool) {
if deadline, ok = mc.ctx1.Deadline(); ok {
return deadline, ok
}
if deadline, ok = mc.ctx2.Deadline(); ok {
return deadline, ok
}
return mc.doneCtx.Deadline()
}
func (mc *mergedCtx) Done() <-chan struct{} {
return mc.doneCtx.Done()
}
func (mc *mergedCtx) Err() error {
if err := mc.ctx1.Err(); err != nil {
return mc.ctx1.Err()
}
if err := mc.ctx2.Err(); err != nil {
return mc.ctx2.Err()
}
return mc.doneCtx.Err()
}
func (mc *mergedCtx) Value(key interface{}) interface{} {
if value := mc.ctx1.Value(key); value != nil {
return value
}
if value := mc.ctx2.Value(key); value != nil {
return value
}
return mc.doneCtx.Value(key)
}
type onlyValues struct {
context.Context
}
// OnlyValues returns a derived context that removes deadlines and cancellation,
// but keeps values.
func OnlyValues(ctx context.Context) context.Context {
return onlyValues{ctx}
}
func (o onlyValues) Deadline() (time.Time, bool) {
return time.Time{}, false
}
func (o onlyValues) Done() <-chan struct{} {
return nil
}
func (o onlyValues) Err() error {
return nil
}