metadata.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package metadata
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. )
  7. // MD is a mapping from metadata keys to values.
  8. type MD map[string]interface{}
  9. type mdKey struct{}
  10. // Len returns the number of items in md.
  11. func (md MD) Len() int {
  12. return len(md)
  13. }
  14. // Copy returns a copy of md.
  15. func (md MD) Copy() MD {
  16. return Join(md)
  17. }
  18. // New creates an MD from a given key-value map.
  19. func New(m map[string]interface{}) MD {
  20. md := MD{}
  21. for k, val := range m {
  22. md[k] = val
  23. }
  24. return md
  25. }
  26. // Join joins any number of mds into a single MD.
  27. // The order of values for each key is determined by the order in which
  28. // the mds containing those values are presented to Join.
  29. func Join(mds ...MD) MD {
  30. out := MD{}
  31. for _, md := range mds {
  32. for k, v := range md {
  33. out[k] = v
  34. }
  35. }
  36. return out
  37. }
  38. // Pairs returns an MD formed by the mapping of key, value ...
  39. // Pairs panics if len(kv) is odd.
  40. func Pairs(kv ...interface{}) MD {
  41. if len(kv)%2 == 1 {
  42. panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv)))
  43. }
  44. md := MD{}
  45. var key string
  46. for i, s := range kv {
  47. if i%2 == 0 {
  48. key = s.(string)
  49. continue
  50. }
  51. md[key] = s
  52. }
  53. return md
  54. }
  55. // NewContext creates a new context with md attached.
  56. func NewContext(ctx context.Context, md MD) context.Context {
  57. return context.WithValue(ctx, mdKey{}, md)
  58. }
  59. // FromContext returns the incoming metadata in ctx if it exists. The
  60. // returned MD should not be modified. Writing to it may cause races.
  61. // Modification should be made to copies of the returned MD.
  62. func FromContext(ctx context.Context) (md MD, ok bool) {
  63. md, ok = ctx.Value(mdKey{}).(MD)
  64. return
  65. }
  66. // String get string value from metadata in context
  67. func String(ctx context.Context, key string) string {
  68. md, ok := ctx.Value(mdKey{}).(MD)
  69. if !ok {
  70. return ""
  71. }
  72. str, _ := md[key].(string)
  73. return str
  74. }
  75. // Int64 get int64 value from metadata in context
  76. func Int64(ctx context.Context, key string) int64 {
  77. md, ok := ctx.Value(mdKey{}).(MD)
  78. if !ok {
  79. return 0
  80. }
  81. i64, _ := md[key].(int64)
  82. return i64
  83. }
  84. // Value get value from metadata in context return nil if not found
  85. func Value(ctx context.Context, key string) interface{} {
  86. md, ok := ctx.Value(mdKey{}).(MD)
  87. if !ok {
  88. return nil
  89. }
  90. return md[key]
  91. }
  92. // WithContext return no deadline context and retain metadata.
  93. func WithContext(c context.Context) context.Context {
  94. md, ok := FromContext(c)
  95. if ok {
  96. nmd := md.Copy()
  97. // NOTE: temporary delete prevent asynchronous task reuse finished task
  98. delete(nmd, Trace)
  99. return NewContext(context.Background(), nmd)
  100. }
  101. return context.Background()
  102. }
  103. // Bool get boolean from metadata in context use strconv.Parse.
  104. func Bool(ctx context.Context, key string) bool {
  105. md, ok := ctx.Value(mdKey{}).(MD)
  106. if !ok {
  107. return false
  108. }
  109. switch md[key].(type) {
  110. case bool:
  111. return md[key].(bool)
  112. case string:
  113. ok, _ = strconv.ParseBool(md[key].(string))
  114. return ok
  115. default:
  116. return false
  117. }
  118. }