kratos: add application info (#968)
* add application info * add base context * add client targetpull/970/head
parent
7f835db398
commit
149fc0195e
@ -0,0 +1,23 @@ |
||||
package kratos |
||||
|
||||
import "context" |
||||
|
||||
// AppInfo is application context value.
|
||||
type AppInfo struct { |
||||
ID string |
||||
Name string |
||||
Version string |
||||
} |
||||
|
||||
type appKey struct{} |
||||
|
||||
// NewContext returns a new Context that carries value.
|
||||
func NewContext(ctx context.Context, s AppInfo) context.Context { |
||||
return context.WithValue(ctx, appKey{}, s) |
||||
} |
||||
|
||||
// FromContext returns the Transport value stored in ctx, if any.
|
||||
func FromContext(ctx context.Context) (s AppInfo, ok bool) { |
||||
s, ok = ctx.Value(appKey{}).(AppInfo) |
||||
return |
||||
} |
@ -0,0 +1,115 @@ |
||||
package context |
||||
|
||||
import ( |
||||
"context" |
||||
"sync" |
||||
"sync/atomic" |
||||
"time" |
||||
) |
||||
|
||||
type mergeCtx struct { |
||||
parent1, parent2 context.Context |
||||
|
||||
done chan struct{} |
||||
doneMark uint32 |
||||
doneOnce sync.Once |
||||
doneErr error |
||||
|
||||
cancelCh chan struct{} |
||||
cancelOnce sync.Once |
||||
} |
||||
|
||||
// Merge merges two contexts into one.
|
||||
func Merge(parent1, parent2 context.Context) (context.Context, context.CancelFunc) { |
||||
mc := &mergeCtx{ |
||||
parent1: parent1, |
||||
parent2: parent2, |
||||
done: make(chan struct{}), |
||||
cancelCh: make(chan struct{}), |
||||
} |
||||
select { |
||||
case <-parent1.Done(): |
||||
mc.finish(parent1.Err()) |
||||
case <-parent2.Done(): |
||||
mc.finish(parent2.Err()) |
||||
default: |
||||
go mc.wait() |
||||
} |
||||
return mc, mc.cancel |
||||
} |
||||
|
||||
func (mc *mergeCtx) finish(err error) error { |
||||
mc.doneOnce.Do(func() { |
||||
mc.doneErr = err |
||||
atomic.StoreUint32(&mc.doneMark, 1) |
||||
close(mc.done) |
||||
}) |
||||
return mc.doneErr |
||||
} |
||||
|
||||
func (mc *mergeCtx) wait() { |
||||
var err error |
||||
select { |
||||
case <-mc.parent1.Done(): |
||||
err = mc.parent1.Err() |
||||
case <-mc.parent2.Done(): |
||||
err = mc.parent2.Err() |
||||
case <-mc.cancelCh: |
||||
err = context.Canceled |
||||
} |
||||
mc.finish(err) |
||||
} |
||||
|
||||
func (mc *mergeCtx) cancel() { |
||||
mc.cancelOnce.Do(func() { |
||||
close(mc.cancelCh) |
||||
}) |
||||
} |
||||
|
||||
// Done implements context.Context.
|
||||
func (mc *mergeCtx) Done() <-chan struct{} { |
||||
return mc.done |
||||
} |
||||
|
||||
// Err implements context.Context.
|
||||
func (mc *mergeCtx) Err() error { |
||||
if atomic.LoadUint32(&mc.doneMark) != 0 { |
||||
return mc.doneErr |
||||
} |
||||
var err error |
||||
select { |
||||
case <-mc.parent1.Done(): |
||||
err = mc.parent1.Err() |
||||
case <-mc.parent2.Done(): |
||||
err = mc.parent2.Err() |
||||
case <-mc.cancelCh: |
||||
err = context.Canceled |
||||
default: |
||||
return nil |
||||
} |
||||
return mc.finish(err) |
||||
} |
||||
|
||||
// Deadline implements context.Context.
|
||||
func (mc *mergeCtx) Deadline() (time.Time, bool) { |
||||
d1, ok1 := mc.parent1.Deadline() |
||||
d2, ok2 := mc.parent2.Deadline() |
||||
switch { |
||||
case !ok1: |
||||
return d2, ok2 |
||||
case !ok2: |
||||
return d1, ok1 |
||||
case d1.Before(d2): |
||||
return d1, true |
||||
default: |
||||
return d2, true |
||||
} |
||||
} |
||||
|
||||
// Value implements context.Context.
|
||||
func (mc *mergeCtx) Value(key interface{}) interface{} { |
||||
if v := mc.parent1.Value(key); v != nil { |
||||
return v |
||||
} |
||||
return mc.parent2.Value(key) |
||||
} |
Loading…
Reference in new issue