github.com/aaabigfish/gopkg@v1.1.0/cloud/metainfo/info.go (about)

     1  // Copyright 2021 ByteDance Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package metainfo
    16  
    17  import (
    18  	"context"
    19  )
    20  
    21  // The prefix listed below may be used to tag the types of values when there is no context to carry them.
    22  const (
    23  	PrefixPersistent         = "RPC_PERSIST_"
    24  	PrefixTransient          = "RPC_TRANSIT_"
    25  	PrefixTransientUpstream  = "RPC_TRANSIT_UPSTREAM_"
    26  	PrefixBackward           = "RPC_BACKWARD_"
    27  	PrefixBackwardDownstream = "RPC_BACKWARD_DOWNSTREAM_"
    28  
    29  	lenPTU = len(PrefixTransientUpstream)
    30  	lenPT  = len(PrefixTransient)
    31  	lenPP  = len(PrefixPersistent)
    32  	lenB   = len(PrefixBackward)
    33  	lenBD  = len(PrefixBackwardDownstream)
    34  )
    35  
    36  // **Using empty string as key or value is not support.**
    37  
    38  // TransferForward converts transient values to transient-upstream values and filters out original transient-upstream values.
    39  // It should be used before the context is passing from server to client.
    40  func TransferForward(ctx context.Context) context.Context {
    41  	if n := getNode(ctx); n != nil {
    42  		return withNode(ctx, n.transferForward())
    43  	}
    44  	return ctx
    45  }
    46  
    47  // GetValue retrieves the value set into the context by the given key.
    48  func GetValue(ctx context.Context, k string) (v string, ok bool) {
    49  	if n := getNode(ctx); n != nil {
    50  		if idx, ok := search(n.transient, k); ok {
    51  			return n.transient[idx].val, true
    52  		}
    53  		if idx, ok := search(n.stale, k); ok {
    54  			return n.stale[idx].val, true
    55  		}
    56  	}
    57  	return
    58  }
    59  
    60  // GetAllValues retrieves all transient values
    61  func GetAllValues(ctx context.Context) (m map[string]string) {
    62  	if n := getNode(ctx); n != nil {
    63  		if cnt := len(n.stale) + len(n.transient); cnt > 0 {
    64  			m = make(map[string]string, cnt)
    65  			for _, kv := range n.stale {
    66  				m[kv.key] = kv.val
    67  			}
    68  			for _, kv := range n.transient {
    69  				m[kv.key] = kv.val
    70  			}
    71  		}
    72  	}
    73  	return
    74  }
    75  
    76  // RangeValues calls f sequentially for each transient kv.
    77  // If f returns false, range stops the iteration.
    78  func RangeValues(ctx context.Context, f func(k, v string) bool) {
    79  	n := getNode(ctx)
    80  	if n == nil {
    81  		return
    82  	}
    83  
    84  	if cnt := len(n.stale) + len(n.transient); cnt == 0 {
    85  		return
    86  	}
    87  
    88  	for _, kv := range n.stale {
    89  		if !f(kv.key, kv.val) {
    90  			return
    91  		}
    92  	}
    93  
    94  	for _, kv := range n.transient {
    95  		if !f(kv.key, kv.val) {
    96  			return
    97  		}
    98  	}
    99  }
   100  
   101  // WithValue sets the value into the context by the given key.
   102  // This value will be propagated to the next service/endpoint through an RPC call.
   103  //
   104  // Notice that it will not propagate any further beyond the next service/endpoint,
   105  // Use WithPersistentValue if you want to pass a key/value pair all the way.
   106  func WithValue(ctx context.Context, k, v string) context.Context {
   107  	if len(k) == 0 || len(v) == 0 {
   108  		return ctx
   109  	}
   110  	if n := getNode(ctx); n != nil {
   111  		if m := n.addTransient(k, v); m != n {
   112  			return withNode(ctx, m)
   113  		}
   114  	} else {
   115  		return withNode(ctx, &node{
   116  			transient: []kv{{key: k, val: v}},
   117  		})
   118  	}
   119  	return ctx
   120  }
   121  
   122  // DelValue deletes a key/value from the current context.
   123  // Since empty string value is not valid, we could just set the value to be empty.
   124  func DelValue(ctx context.Context, k string) context.Context {
   125  	if len(k) == 0 {
   126  		return ctx
   127  	}
   128  	if n := getNode(ctx); n != nil {
   129  		if m := n.delTransient(k); m != n {
   130  			return withNode(ctx, m)
   131  		}
   132  	}
   133  	return ctx
   134  }
   135  
   136  // GetPersistentValue retrieves the persistent value set into the context by the given key.
   137  func GetPersistentValue(ctx context.Context, k string) (v string, ok bool) {
   138  	if n := getNode(ctx); n != nil {
   139  		if idx, ok := search(n.persistent, k); ok {
   140  			return n.persistent[idx].val, true
   141  		}
   142  	}
   143  	return
   144  }
   145  
   146  // GetAllPersistentValues retrieves all persistent values.
   147  func GetAllPersistentValues(ctx context.Context) (m map[string]string) {
   148  	if n := getNode(ctx); n != nil {
   149  		if cnt := len(n.persistent); cnt > 0 {
   150  			m = make(map[string]string, cnt)
   151  			for _, kv := range n.persistent {
   152  				m[kv.key] = kv.val
   153  			}
   154  		}
   155  	}
   156  	return
   157  }
   158  
   159  // RangePersistentValues calls f sequentially for each persistent kv.
   160  // If f returns false, range stops the iteration.
   161  func RangePersistentValues(ctx context.Context, f func(k, v string) bool) {
   162  	n := getNode(ctx)
   163  	if n == nil {
   164  		return
   165  	}
   166  
   167  	for _, kv := range n.persistent {
   168  		if !f(kv.key, kv.val) {
   169  			break
   170  		}
   171  	}
   172  }
   173  
   174  // WithPersistentValue sets the value into the context by the given key.
   175  // This value will be propagated to the services along the RPC call chain.
   176  func WithPersistentValue(ctx context.Context, k, v string) context.Context {
   177  	if len(k) == 0 || len(v) == 0 {
   178  		return ctx
   179  	}
   180  	if n := getNode(ctx); n != nil {
   181  		if m := n.addPersistent(k, v); m != n {
   182  			return withNode(ctx, m)
   183  		}
   184  	} else {
   185  		return withNode(ctx, &node{
   186  			persistent: []kv{{key: k, val: v}},
   187  		})
   188  	}
   189  	return ctx
   190  }
   191  
   192  // DelPersistentValue deletes a persistent key/value from the current context.
   193  // Since empty string value is not valid, we could just set the value to be empty.
   194  func DelPersistentValue(ctx context.Context, k string) context.Context {
   195  	if len(k) == 0 {
   196  		return ctx
   197  	}
   198  	if n := getNode(ctx); n != nil {
   199  		if m := n.delPersistent(k); m != n {
   200  			return withNode(ctx, m)
   201  		}
   202  	}
   203  	return ctx
   204  }
   205  
   206  func getKey(kvs []string, i int) string {
   207  	return kvs[i*2]
   208  }
   209  
   210  func getValue(kvs []string, i int) string {
   211  	return kvs[i*2+1]
   212  }
   213  
   214  // WithPersistentValues sets the values into the context by the given keys.
   215  // This value will be propagated to the services along the RPC call chain.
   216  func WithPersistentValues(ctx context.Context, kvs ...string) context.Context {
   217  	if len(kvs)%2 != 0 {
   218  		panic("len(kvs) must be even")
   219  	}
   220  
   221  	kvLen := len(kvs) / 2
   222  
   223  	if ctx == nil || len(kvs) == 0 {
   224  		return ctx
   225  	}
   226  
   227  	var n *node
   228  	if m := getNode(ctx); m != nil {
   229  		nn := *m
   230  		n = &nn
   231  		n.persistent = make([]kv, 0, len(m.persistent)+kvLen)
   232  		copy(n.persistent, m.persistent)
   233  	} else {
   234  		n = &node{
   235  			persistent: make([]kv, 0, kvLen),
   236  		}
   237  	}
   238  
   239  	for i := 0; i < kvLen; i++ {
   240  		key := getKey(kvs, i)
   241  		val := getValue(kvs, i)
   242  
   243  		if len(key) == 0 || len(val) == 0 {
   244  			continue
   245  		}
   246  
   247  		if idx, ok := search(n.persistent, key); ok {
   248  			if n.persistent[idx].val != val {
   249  				n.persistent[idx].val = val
   250  			}
   251  		} else {
   252  			n.persistent = append(n.persistent, kv{key: key, val: val})
   253  		}
   254  	}
   255  
   256  	return withNode(ctx, n)
   257  }
   258  
   259  // WithValue sets the values into the context by the given keys.
   260  // This value will be propagated to the next service/endpoint through an RPC call.
   261  //
   262  // Notice that it will not propagate any further beyond the next service/endpoint,
   263  // Use WithPersistentValues if you want to pass key/value pairs all the way.
   264  func WithValues(ctx context.Context, kvs ...string) context.Context {
   265  	if len(kvs)%2 != 0 {
   266  		panic("len(kvs) must be even")
   267  	}
   268  
   269  	kvLen := len(kvs) / 2
   270  
   271  	if ctx == nil || len(kvs) == 0 {
   272  		return ctx
   273  	}
   274  
   275  	var n *node
   276  	if m := getNode(ctx); m != nil {
   277  		nn := *m
   278  		n = &nn
   279  		n.transient = make([]kv, 0, len(m.transient)+kvLen)
   280  		copy(n.transient, m.transient)
   281  	} else {
   282  		n = &node{
   283  			transient: make([]kv, 0, kvLen),
   284  		}
   285  	}
   286  
   287  	for i := 0; i < kvLen; i++ {
   288  		key := getKey(kvs, i)
   289  		val := getValue(kvs, i)
   290  
   291  		if len(key) == 0 || len(val) == 0 {
   292  			continue
   293  		}
   294  
   295  		if res, ok := remove(n.stale, key); ok {
   296  			n.stale = res
   297  			n.transient = append(n.transient, kv{key: key, val: val})
   298  			continue
   299  		}
   300  
   301  		if idx, ok := search(n.transient, key); ok {
   302  			if n.transient[idx].val != val {
   303  				n.transient[idx].val = val
   304  			}
   305  		} else {
   306  			n.transient = append(n.transient, kv{key: key, val: val})
   307  		}
   308  	}
   309  
   310  	return withNode(ctx, n)
   311  }